﻿using System;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.IO.Compression;

//c:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\WinUser.h

namespace PickGold.Api
{
	static class Common
	{
	}
	/// <summary>
	/// Api 通用类
	/// </summary>
	public static class ApiUtil
	{
		internal const string DLL_URLMON = "urlmon.dll";
		internal const string DLL_GDI32 = "gdi32.dll";
		internal const string DLL_GDIPLUS = "gdiplus.dll";
		internal const string DLL_SETUPAPI = "setupapi.dll";
		internal const string DLL_HID = "hid.dll";
		internal const string DLL_MPR = "mpr.dll";
		/// <summary>
		/// kernel32.dll
		/// </summary>
		internal const string DLL_KERNEL32 = "kernel32.dll";
		internal const string DLL_USER32 = "user32.dll";
		internal const string DLL_MSVFW32 = "MSVFW32.dll";
		internal const string DLL_OLE32 = "ole32.dll";
		internal const string DLL_SHELL32 = "shell32.dll";
		internal const string DLL_WINMM = "winmm.dll";
		internal const string DLL_WINUSB = "winusb.dll";
		internal const string DLL_WININET = "wininet.dll";
		internal const string DLL_RASAPI32 = "rasapi32.dll";
		internal const string DLL_WINSPOOL = "winspool.drv";

		/// <summary/>
		public const int METHOD_BUFFERED = 0;

		/// <summary>
		/// Monitor Power
		/// </summary>
		/// <returns>return SendMessage(Handle, 0x0112, 0xF170, 2)</returns>
		public static IntPtr MonitorPower()
		{
			return ApiUtil.MonitorPower(false);
		}
		/// <summary>
		/// Monitor Power
		/// </summary>
		/// <param name="on">on ? -1 : 2</param>
		/// <returns>return SendMessage(Handle, 0x0112, 0xF170, on ? -1 : 2)</returns>
		public static IntPtr MonitorPower(bool on)
		{
			return User32.SendMessage(System.Diagnostics.Process.GetCurrentProcess().Handle, WM.SYSCOMMAND, SC.MONITORPOWER, on ? -1 : 2);
		}

		/// <summary>
		/// GetApiEntryPoint DllImportAttribute::EntryPoint
		/// </summary>
		/// <param name="method">MethodBase</param>
		/// <returns>DllImportAttribute::EntryPoint Or MethodBase::Name</returns>
		public static string GetApiEntryPoint(this MethodBase method)
		{
			var os = method.GetCustomAttributes(typeof(DllImportAttribute), true);
			if (os == null || os.Length == 0)
				return null;

			if (os.Length == 1)
			{
				var dia = os[0] as DllImportAttribute;
				if (dia == null)
					return null;

				if (string.IsNullOrEmpty(dia.EntryPoint))
					return method.Name;

				return dia.EntryPoint;
			}

			foreach (var o in os)
			{
				if (o == null)
					continue;

				var dia = o as DllImportAttribute;
				if (dia != null && !string.IsNullOrEmpty(dia.EntryPoint))
					return dia.EntryPoint;
			}

			return method.Name;
		}

		/// <summary>
		/// 结构转字节流
		/// </summary>
		/// <param name="value"></param>
		/// <param name="data"></param>
		/// <param name="offset"></param>
		/// <param name="length">为零为自动计算</param>
		/// <returns></returns>
		public static byte[] StructToBytes(object value, byte[] data, int offset, int length)
		{
			if(length == 0)
				length = Marshal.SizeOf(value);
			if(data == null)
				data = new byte[length];
			var buffer = Marshal.AllocHGlobal(length);
			Marshal.StructureToPtr(value, buffer, false);
			Marshal.Copy(buffer, data, offset, length);
			Marshal.FreeHGlobal(buffer);
			return data;
		}

		/// <summary>
		/// 字节流转结构
		/// </summary>
		/// <param name="data"></param>
		/// <param name="offset"></param>
		/// <param name="length">为零为自动计算</param>
		/// <param name="type"></param>
		/// <returns></returns>
		public static object BytesToStruct(byte[] data, int offset, int length, Type type)
		{
			if (length == 0)
				length = Marshal.SizeOf(type);
			var buffer = Marshal.AllocHGlobal(length);
			Marshal.Copy(data, offset, buffer, length);
			var v = Marshal.PtrToStructure(buffer, type);
			Marshal.FreeHGlobal(buffer);
			return v;
		}

		/// <summary>
		/// 字节流转结构
		/// </summary>
		/// <param name="data"></param>
		/// <param name="offset"></param>
		/// <param name="length">为零为自动计算</param>
		/// <param name="value"></param>
		public static object BytesToStruct(byte[] data, int offset, int length, object value)
		{
			if(length == 0)
				length = Marshal.SizeOf(value);
			var buffer = Marshal.AllocHGlobal(length);
			Marshal.Copy(data, offset, buffer, length);
			Marshal.PtrToStructure(buffer, value);
			Marshal.FreeHGlobal(buffer);
			return value;
		}

		/// <summary>
		/// 字节流转结构
		/// </summary>
		/// <param name="data"></param>
		/// <param name="value"></param>
		public static object BytesToStruct(byte[] data, object value)
		{
			return BytesToStruct(data, 0, 0, value);
		}

		/// <summary>
		/// 字节流转结构
		/// </summary>
		/// <param name="data"></param>
		/// <param name="type"></param>
		/// <returns></returns>
		public static object BytesToStruct(byte[] data, Type type)
		{
			return BytesToStruct(data, 0, 0, type);
		}

		/// <summary>
		/// 取PE文件实际大小
		/// </summary>
		/// <param name="file"></param>
		/// <returns></returns>
		public static long GetPortableExecutableSize(Stream file)
		{
			var i = Marshal.SizeOf(typeof(IMAGE_DOS_HEADER));
			var bs = new byte[i];
			if (file.Read(bs, 0, i) != i)
				return -1;

			if (bs[0] != AsciiCode.M || bs[1] != AsciiCode.Z)
				return -2;

			file.Seek(BitConverter.ToUInt32(bs, i - 4), SeekOrigin.Begin);
			i = Marshal.SizeOf(typeof(IMAGE_FILE_HEADER)) + 4;
			bs = new byte[i];
			if (file.Read(bs, 0, i) != i)
				return -3;

			if (bs[0] != AsciiCode.P || bs[1] != AsciiCode.E)
				return -4;

			i = Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER));
			file.Seek(BitConverter.ToUInt16(bs, 20) + (BitConverter.ToUInt16(bs, 6) - 1) * i, SeekOrigin.Current);
			bs = new byte[i];
			if (file.Read(bs, 0, i) != i)
				return -5;

			return BitConverter.ToUInt32(bs, 16) + BitConverter.ToUInt32(bs, 20);
		}

		/// <summary>
		/// 取PE文件实际大小
		/// </summary>
		/// <param name="file"></param>
		/// <returns></returns>
		public static long GetPortableExecutableSize(string file)
		{
			using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
				return GetPortableExecutableSize(fs);
		}

		/// <summary>
		/// 取PE文件实际大小
		/// </summary>
		/// <param name="file"></param>
		/// <returns></returns>
		[Obsolete("See GetPortableExecutableSize")]
		public static long GetPortableExecutableReal(string file)
		{
			var i = Marshal.SizeOf(typeof(IMAGE_DOS_HEADER));
			var bs = new byte[i];
			using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
			{
				i = fs.Read(bs, 0, i);
				var dh = (IMAGE_DOS_HEADER)ApiUtil.BytesToStruct(bs, 0, i, typeof(IMAGE_DOS_HEADER));

				fs.Seek(dh.e_lfanew, SeekOrigin.Begin);
				i = fs.Read(bs, 0, 4);// p e 00 00

				i = Marshal.SizeOf(typeof(IMAGE_FILE_HEADER));
				bs = new byte[i];
				i = fs.Read(bs, 0, i);
				var ph = (IMAGE_FILE_HEADER)ApiUtil.BytesToStruct(bs, 0, i, typeof(IMAGE_FILE_HEADER));

				//i = Marshal.SizeOf(typeof(IMAGE_OPTIONAL_HEADER32));
				bs = new byte[ph.SizeOfOptionalHeader];
				i = fs.Read(bs, 0, ph.SizeOfOptionalHeader);
				var oh = (IMAGE_OPTIONAL_HEADER32)ApiUtil.BytesToStruct(bs, 0, i, typeof(IMAGE_OPTIONAL_HEADER32));

				i = Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER));
				var v = fs.Position + ph.NumberOfSections * i;
				if (v % oh.FileAlignment > 0)
					v = (v / oh.FileAlignment) * oh.FileAlignment + oh.FileAlignment;

				bs = new byte[i];
				for (var ii = 0; ii < ph.NumberOfSections; ii++)
				{
					if (fs.Read(bs, 0, i) != i)
						break;

					v += BitConverter.ToUInt32(bs, 16);
				}

				return v;
			}
		}

		/// <summary>
		/// 列表
		/// </summary>
		/// <param name="file">自解压文件名；空为当前执行文件。</param>
		/// <param name="output">输出方法的委托</param>
		/// <returns>返回零表示成功</returns>
		public static string PortableExecutablePacketList(string file, Action<string> output)
		{
			var t = file;
			if (string.IsNullOrWhiteSpace(t))
				t = PickGold.Common.ExecutablePath;
			else
				t = Path.GetFullPath(Environment.ExpandEnvironmentVariables(t));
			using (var fs = File.Open(t, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
			{
				var l = ApiUtil.GetPortableExecutableSize(fs);
				if (l <= 0)
				{
					fs.Close();
					return null;
				}

				var sb = new StringBuilder();
				var bs = new byte[byte.MaxValue];
				fs.Seek(l, SeekOrigin.Begin);
				sb.Append("<" + Path.GetFileName(fs.Name) + ">");
				t = string.Format(@"<o{0} time=""{1:s}"" size=""{2}"" offset=""{3}"">{4}</o{0}>", 0, File.GetLastWriteTimeUtc(t), l, 0, Path.GetFileName(t));
				output(t);
				sb.Append(t);
				Tracker.WriteLine(t);
				for (var i = 1; ; i++)
				{
					if (fs.Read(bs, 0, 4) != 4)//内容长度
						break;

					var s = BitConverter.ToUInt32(bs, 0);
					if (fs.Read(bs, 0, 8) != 8)//取文件名长度与最后修改时间
						break;

					var w = BitConverter.ToUInt64(bs, 0);
					var n = (ushort)(w >> 48);
					if (n > 0)
					{
						if (fs.Read(bs, 0, n) != n)
							break;

						s = s - n - 8;
						t = Encoding.UTF8.GetString(bs, 0, n);
						t = string.Format(@"<o{0} time=""{1:s}"" size=""{2}"" offset=""{3}"">{4}</o{0}>", i, PickGold.Common.GetJsDate((double)(w - ((ulong)n << 48))), s, fs.Position, t);
					}
					else
					{
						t = string.Format(@"<o{0} time=""{1:s}"" size=""{2}"" offset=""{3}""/>", i, PickGold.Common.GetJsDate((double)(w - ((ulong)n << 48))), s, fs.Position);
					}
					output(t);
					sb.Append(t);
					Tracker.WriteLine(t);
					fs.Seek(s, SeekOrigin.Current);
				}
				sb.Append("</" + Path.GetFileName(fs.Name) + ">");
				fs.Close();
				t = sb.ToString();
			}
			return t;
		}
		/// <summary>
		/// 解压
		/// </summary>
		/// <param name="file">要解压的文件</param>
		/// <param name="target">目标文件夹</param>
		/// <param name="index">只解压指定索引处的文件；小于零表示仅复制源PE部分；等于零表示解压所有；</param>
		/// <returns>返回零表示成功</returns>
		public static string PortableExecutableUnpacket(string file, string target, int index = 0)
		{
			if (string.IsNullOrWhiteSpace(file))
				file = PickGold.Common.ExecutablePath;
			else
				file = Path.GetFullPath(Environment.ExpandEnvironmentVariables(file));
			if (string.IsNullOrWhiteSpace(target))
				target = Path.Combine(Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(file));
			else
				target = Path.GetFullPath(Environment.ExpandEnvironmentVariables(target));
			using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
			{
				var l = ApiUtil.GetPortableExecutableSize(fs);//PE长度
				if (l <= 0)
				{
					fs.Close();
					return null;
				}

				var bs = new byte[BitUtil.K];
				var ls = new LimitStream(fs, l > fs.Length ? fs.Length : l, true);
				var t = Path.Combine(target, Path.GetFileName(file));
				if (index <= 0 && string.Compare(t, PickGold.Common.ExecutablePath, StringComparison.OrdinalIgnoreCase) != 0)//取原PE
				{
					if (!Directory.Exists(Path.GetDirectoryName(t)))
						Directory.CreateDirectory(Path.GetDirectoryName(t));
					using (var ts = File.Open(t, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
					{
						fs.Seek(0L, SeekOrigin.Begin);
						for (;;)
						{
							var i = ls.Read(bs, 0, BitUtil.K);
							if (i == 0)
								break;

							ts.Write(bs, 0, i);
						}
						ts.Close();
					}
					File.SetLastWriteTimeUtc(t, File.GetLastWriteTimeUtc(file));
					if (index < 0)
						return t;

					if (l >= fs.Length)
					{
						fs.Close();
						return target;
					}
				}
				else
				{
					if (l >= fs.Length)
					{
						fs.Close();
						return null;
					}

					fs.Seek(l, SeekOrigin.Begin);
				}
				for (var i = 1; ; i++)
				{
					if (fs.Read(bs, 0, 4) != 4)//内容长度
						break;

					var s = BitConverter.ToUInt32(bs, 0);
					if (index > 0 && index != i)
					{
						fs.Seek(s, SeekOrigin.Current);
						continue;
					}

					if (fs.Read(bs, 0, 8) != 8)//取文件名长度与最后修改时间
						break;

					var w = BitConverter.ToUInt64(bs, 0);
					var n = (ushort)(w >> 48);//文件名长度
					if (n > ushort.MinValue)
					{
						if (fs.Read(bs, 0, n) != n)
							break;

						t = Encoding.UTF8.GetString(bs, 0, n);
					}
					else
					{
						t = i.ToString();
					}
					s = s - n - 8U;
					if (t.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
					{
						if (s > 0)
							fs.Seek(s, SeekOrigin.Current);
					}
					else
					{
						t = Path.Combine(target, t);
						if (!Directory.Exists(Path.GetDirectoryName(t)))
							Directory.CreateDirectory(Path.GetDirectoryName(t));
						using (var ts = File.Open(t, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
						{
							ls.Reset(fs, s, true);
							if (ls.Length > 0L)
							{
								using (var zs = new GZipStream(ls, CompressionMode.Decompress, true))
								{
									for (;;)
									{
										var r = zs.Read(bs, 0, BitUtil.K);
										if (r == 0)
											break;

										ts.Write(bs, 0, r);
									}
									zs.Close();
								}
							}
							ts.Close();
						}
						w = w - ((ulong)n << 48);
						if (w > ulong.MinValue)
							File.SetLastWriteTimeUtc(t, PickGold.Common.GetJsDate((double)w));
					}
					if (index > 0)
					{
						index = int.MinValue;
						target = t;
						break;
					}

					index--;
				}
				ls.Close();
				fs.Close();
			}
			if (index >= 0)
				return string.Empty;

			return target;
		}
		/// <summary>
		/// 压缩
		/// </summary>
		/// <param name="args">第一个为目标文件名；后续参数可为文件也可为目录，如果要重命名则需要使用 /&lt;New-Name&gt;: 作为前缀；</param>
		/// <returns>返回零表示成功</returns>
		public static string PortableExecutablePacket(params string[] args)
		{
			var bs = new byte[BitUtil.K];
			if (!string.IsNullOrWhiteSpace(args[0]))
			{
				args[0] = Path.GetFullPath(Environment.ExpandEnvironmentVariables(args[0]));
				if (Directory.Exists(args[0]))
					args[0] = Path.Combine(args[0], Path.GetFileName(PickGold.Common.ExecutablePath));
			}
			else
			{
				if (string.Compare(args[0], PickGold.Common.ExecutablePath, StringComparison.OrdinalIgnoreCase) == 0)
					args[0] = Path.Combine(Path.GetDirectoryName(PickGold.Common.ExecutablePath), Path.GetFileNameWithoutExtension(PickGold.Common.ExecutablePath) + Path.GetExtension(PickGold.Common.ExecutablePath) + Path.GetExtension(PickGold.Common.ExecutablePath));
			}
			if (!Directory.Exists(Path.GetDirectoryName(args[0])))
				Directory.CreateDirectory(Path.GetDirectoryName(args[0]));
			if (!File.Exists(args[0]))
				File.Copy(PickGold.Common.ExecutablePath, args[0], true);
			using (var fs = File.Open(args[0], FileMode.Append, FileAccess.Write, FileShare.Read))
			{
				for (var i = 1; i < args.Length; i++)
				{
					if (string.IsNullOrWhiteSpace(args[i]))
						continue;

					if (args[i][0] == '/' && args[i].IndexOf(':') > 0)
					{
						var ii = args[i].Replace(AsciiChar.QUOTATION, v => string.Empty.PadLeft(v.Length, AsciiChar.SP)).IndexOf(':');
						PortableExecutablePacket(fs, bs, args[i].Substring(ii + 1).Trim(), args[i].Substring(1, ii - 1));
						continue;
					}

					if (Directory.Exists(args[i]))
					{
						foreach (var f in Directory.GetFiles(args[i], "*.*", SearchOption.AllDirectories))
							PortableExecutablePacket(fs, bs, f, f.Substring(args[i].Length + 1));
						continue;
					}

					PortableExecutablePacket(fs, bs, args[i], Path.GetFileName(args[i]));
				}
				fs.Close();
			}
			return args[0];
		}
		/// <summary>
		/// 压缩单个文件
		/// </summary>
		private static int PortableExecutablePacket(Stream target, byte[] buffer, string file, string name)
		{
			if (string.IsNullOrWhiteSpace(file) || file.IndexOfAny(Path.GetInvalidPathChars()) >= 0 || !File.Exists(file))
			{
				if (string.IsNullOrWhiteSpace(name))
					return -1;

				var ns = Encoding.UTF8.GetBytes(name);
				target.Write(BitConverter.GetBytes((uint)(ns.Length + 8L)), 0, 4);//写内容总长度：文件名长度，最后修改时间与文件名长度标记
				target.Write(BitConverter.GetBytes(((ulong)ns.Length << 48)), 0, 8);//写入文件名长度，后面的空字节表示文件最后写入的Unix时间
				target.Write(ns, 0, ns.Length);//写入文件名
				return 0;
			}

			var w = File.GetLastWriteTimeUtc(file);
			if (name == null)
				name = Path.GetFileNameWithoutExtension(file);
			using (var s = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))//预压缩文件
			{
				file = Path.GetTempFileName();
				using (var t = File.Open(file, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))//临时压缩文件
				{
					using (var z = new GZipStream(t, CompressionMode.Compress, true))
					{
						for (;;)
						{
							var i = s.Read(buffer, 0, BitUtil.K);
							if (i == 0)
								break;

							z.Write(buffer, 0, i);
						}
						z.Close();
					}
					t.Close();
				}
				s.Close();
			}
			using (var s = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
			{
				var ns = string.IsNullOrWhiteSpace(name) ? Reflector<byte>.EmptyArray : Encoding.UTF8.GetBytes(name);
				target.Write(BitConverter.GetBytes((uint)(s.Length + ns.Length + 8L)), 0, 4);//写内容总长度：文件长度，文件名长度，最后修改时间与文件名长度标记
				target.Write(BitConverter.GetBytes(((ulong)ns.Length << 48) + (ulong)w.GetJsTicks()), 0, 8);//写入文件名，同时后面的字节表示文件最后写入的Unix时间
				if (ns.Length > 0)
					target.Write(ns, 0, ns.Length);//写入文件名
				for (;;)
				{
					var i = s.Read(buffer, 0, BitUtil.K);
					if (i == 0)
						break;

					target.Write(buffer, 0, i);
				}
				s.Close();
			}
			File.Delete(file);
			return 0;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sessionMode"></param>
		/// <param name="session"></param>
		/// <param name="reserved"></param>
		//[DllImport(DLL_URLMON)]
		//public static extern void CoInternetGetSession(int sessionMode, out IInternetSession session, int reserved);

	}

	#region public static class WinInet

	/// <summary>
	/// wininet.dll
	/// </summary>
	public static class WinInet
	{
		/// <summary>
		/// 要删除的类型
		/// </summary>
		public enum DEL_CACHE_TYPE
		{
			/// <summary>
			/// 表示internet临时文件
			/// </summary>
			File,
			/// <summary>
			/// 表示Cookie
			/// </summary>
			Cookie
		}

		/// <summary>
		/// wininet.dll
		/// </summary>
		public const string DLL = ApiUtil.DLL_WININET;

		public const int INTERNET_DIALSTATE_DISCONNECTED = 1;
		public const int INTERNET_AUTODIAL_FORCE_ONLINE = 1;
		public const int INTERNET_AUTODIAL_FORCE_UNATTENDED = 2;
		public const int INTERNET_DIAL_UNATTENDED = 0x8000;
		/// <summary>
		/// 本系统使用调制解调器与因特网相连
		/// </summary>
		public const int INTERNET_CONNECTION_MODEM = 0x01;
		/// <summary>
		/// 本系统通过LAN与因特网相连
		/// </summary>
		public const int INTERNET_CONNECTION_LAN = 0x02;
		/// <summary>
		/// 本系统使用proxy代理服务器与因特网相连
		/// </summary>
		public const int INTERNET_CONNECTION_PROXY = 0x04;
		public const int INTERNET_CONNECTION_MODEM_BUSY = 0x08;
		public const int INTERNET_RAS_INSTALLED = 0x10;
		public const int INTERNET_CONNECTION_OFFLINE = 0x20;
		public const int INTERNET_CONNECTION_CONFIGURED = 0x40;

		public const int AUTODIAL_MODE_NEVER = 1;
		public const int AUTODIAL_MODE_ALWAYS = 2;
		public const int AUTODIAL_MODE_NO_NETWORK_PRESENT = 4;

		/// <summary/>
		[DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true)]
		public static extern bool InternetSetCookie(string lpszUrlName, string lbszCookieName, string lpszCookieData);

		/// <summary/>
		[DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true)]
		public static extern int InternetSetCookieEx(string lpszURL, string lpszCookieName, string lpszCookieData, int dwFlags, IntPtr dwReserved);

		/// <summary/>
		[DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true)]
		public static extern bool InternetGetCookieEx(string pchURL, string pchCookieName, StringBuilder pchCookieData, ref int pcchCookieData, int dwFlags, object lpReserved);

		/// <summary>
		/// InternetGetConnectedState
		/// </summary>
		/// <param name="lpdwFlags">?</param>
		/// <param name="dwReserved">0</param>
		/// <returns></returns>
		[DllImport(DLL)]
		public static extern int InternetGetConnectedState([In][Out][MarshalAs(UnmanagedType.U4)] ref int lpdwFlags, int dwReserved);

		/// <summary/>
		[DllImport(DLL)]//, CharSet = CharSet.Auto, EntryPoint = "InternetGetConnectedStateExW"
		public static extern int InternetGetConnectedStateEx([Out]out int lpdwFlags, [Out]out string lpszConnectionName, int dwNameLen, int dwReserved);// [MarshalAs(UnmanagedType.LPTStr)]

		/// <summary/>
		[DllImport(DLL)]//, CharSet = CharSet.Auto, EntryPoint = "InternetGetConnectedStateExW"
		public static extern int InternetGetConnectedStateEx([Out]out int lpdwFlags, StringBuilder lpszConnectionName, int dwNameLen, int dwReserved);// [MarshalAs(UnmanagedType.LPTStr)]

		/// <summary>
		/// InternetAutoDial
		/// </summary>
		/// <param name="dwFlags">值设为2，该函数无需用户干预就可自动拨号。但使用该函数有一个前提：始终拨打默认连接</param>
		/// <param name="hwndParent">?</param>
		/// <returns>?</returns>
		[DllImport(DLL)]
		public static extern int InternetAutoDial([MarshalAs(UnmanagedType.U4)] int dwFlags, IntPtr hwndParent);

		/// <summary>
		/// InternetAutodialHangup
		/// </summary>
		/// <param name="dwReserved">?</param>
		/// <returns>?</returns>
		[DllImport(DLL)]
		public static extern int InternetAutodialHangup(int dwReserved);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="hwnd"></param>
		/// <param name="lpszConnectoid"></param>
		/// <param name="dwFlags">INTERNET_AUTO_DIAL_UNATTENDED = 2</param>
		/// <param name="lpdwConnection"></param>
		/// <param name="dwReserved"></param>
		/// <returns></returns>
		[DllImport(DLL, CharSet = CharSet.Auto)]
		public extern static int InternetDial(IntPtr hwnd, [In]string lpszConnectoid, uint dwFlags, [Out]out int lpdwConnection, uint dwReserved);

		/// <summary/>
		[DllImport(DLL, CharSet = CharSet.Auto)]
		public extern static int InternetHangUp(int dwConnection, int dwReserved);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="type"></param>
		/// <returns></returns>
		[DllImport(DLL, CharSet = CharSet.Auto)]
		public static extern int DeleteUrlCacheEntry(DEL_CACHE_TYPE type);
	}

	#endregion

	#region public static class RasApi32

	public static class RasApi32
	{
		public struct RASCONN
		{
			public int SizeOfThis()
			{
				dwSize = Marshal.SizeOf(this);
				return dwSize;
			}

			public int dwSize;
			public IntPtr hrasconn;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName + 1)]
			public string szEntryName;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
			public string szDeviceType;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
			public string szDeviceName;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct RasStats
		{
			public int dwSize;
			public int dwBytesXmited;
			public int dwBytesRcved;
			public int dwFramesXmited;
			public int dwFramesRcved;
			public int dwCrcErr;
			public int dwTimeoutErr;
			public int dwAlignmentErr;
			public int dwHardwareOverrunErr;
			public int dwFramingErr;
			public int dwBufferOverrunErr;
			public int dwCompressionRatioIn;
			public int dwCompressionRatioOut;
			public int dwBps;
			public int dwConnectionDuration;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct RasEntryName
		{
			public int dwSize;
			//[MarshalAs(UnmanagedType.ByValTStr,SizeConst=(int)RasFieldSizeConstants.RAS_MaxEntryName + 1)]
			public string szEntryName;
			//#if WINVER5
			// public int dwFlags;
			// [MarshalAs(UnmanagedType.ByValTStr,SizeConst=260+1)]
			// public string szPhonebookPath;
			//#endif
		}

		[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
		public struct RASDIALPARAMS
		{
			public int dwSize;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName + 1)]
			public string szEntryName;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxPhoneNumber + 1)]
			public string szPhoneNumber;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxCallbackNumber + 1)]
			public string szCallbackNumber;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = UNLEN + 1)]
			public string szUserName;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = PWLEN + 1)]
			public string szPassword;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = DNLEN + 1)]
			public string szDomain;
			public int dwSubEntry;
			public int dwCallbackId;
		}

		private const int RAS_MaxDeviceType = 16;
		private const int RAS95_MaxDeviceName = 128;
		private const int RAS95_MaxEntryName = 256;
		private const int RAS_MaxEntryName = 256;
		private const int RAS_MaxPhoneNumber = 16;
		private const int RAS_MaxCallbackNumber = 128;
		private const int UNLEN = 256;
		private const int PWLEN = 256;
		private const int DNLEN = 256;

		public const string DLL = ApiUtil.DLL_RASAPI32;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="lprasconn">buffer to receive connections data</param>
		/// <param name="lpcb">size in bytes of buffer</param>
		/// <param name="lpcConnections">number of connections written to buffer</param>
		/// <returns></returns>
		[DllImport(DLL, EntryPoint = "RasEnumConnectionsA", SetLastError = true)]
		public static extern int RasEnumConnections(ref RASCONN lprasconn, ref int lpcb, ref int lpcConnections);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="hRasConn">handle to the connection</param>
		/// <param name="lpStatistics">buffer to receive statistics</param>
		/// <returns></returns>
		[DllImport(DLL, CharSet = CharSet.Auto)]
		internal static extern uint RasGetConnectionStatistics(IntPtr hRasConn, [In, Out]RasStats lpStatistics);

		//[DllImport("Rasapi32.dll", CharSet = CharSet.Auto)]
		//public static extern int RasDial(int lpRasDialExtensions, string lpszPhonebook, ref   RASDIALPARAMS lprasdialparams, int dwNotifierType, Callback lpvNotifier, ref   int lphRasConn);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="hrasconn">handle to the RAS connection to hang up</param>
		/// <returns></returns>
		[DllImport(DLL, CharSet = CharSet.Auto)]
		public extern static uint RasHangUp(IntPtr hrasconn);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="reserved">reserved, must be NULL</param>
		/// <param name="lpszPhonebook">pointer to full path and file name of phone-book file</param>
		/// <param name="lprasentryname">buffer to receive phone-book entries</param>
		/// <param name="lpcb">size in bytes of buffer</param>
		/// <param name="lpcEntries">number of entries written to buffer</param>
		/// <returns></returns>
		[DllImport(DLL, CharSet = CharSet.Auto)]
		public extern static uint RasEnumEntries(string reserved, string lpszPhonebook, [In, Out]RasEntryName[] lprasentryname, ref int lpcb, out int lpcEntries);
	}

	#endregion

	/// <summary>
	/// 网络映射
	/// </summary>
	public static class Mpr
	{
		/// <summary/>
		public const string DLL = ApiUtil.DLL_MPR;

		/// <summary/>
		[DllImport(DLL)]
		public static extern int WNetAddConnection2A(NET_RESOURCE[] lpNetResource, string lpPassword, string lpUserName, int dwFlags);

		/// <summary/>
		[DllImport(DLL)]
		public static extern int WNetCancelConnection2A(string sharename, int dwFlags, int fForce);

		/// <summary>
		/// 映射网络驱动器
		/// </summary>
		/// <param name="driveLetter">本地盘符，可为空，如果为空则从Z开始自动选择一个未使用的有效盘符；like x:</param>
		/// <param name="sharePath">远程共享路径；like \\192.168.0.2\test</param>
		/// <param name="user">用户名</param>
		/// <param name="password">密码</param>
		/// <returns>本地盘符，如果盘符已被占用，则返回空。</returns>
		public static string Connect(string driveLetter, string sharePath, string user, string password)
		{
			var ds = Directory.GetLogicalDrives();
			if (string.IsNullOrEmpty(driveLetter))
			{
				for (var c = AsciiCode.Z; c >= AsciiCode.A; c--)
				{
					driveLetter = new string(new char[] { (char)c, Path.VolumeSeparatorChar });
					if (!ds.Contains(driveLetter, StringComparer.OrdinalIgnoreCase))
						break;
				}
			}
			else
			{
				if (driveLetter.Length == 1)
					driveLetter += Path.VolumeSeparatorChar;
				if (ds.Contains(driveLetter))
					return null;
			}
			if (driveLetter[0] == AsciiChar.A || driveLetter[0] == AsciiChar.B)
				return null;

			var net = new NET_RESOURCE[1];
			net[0].dwScope = RESOURCE_SCOPE.GLOBALNET;
			net[0].dwType = RESOURCE_TYPE.DISK;
			net[0].dwDisplayType = RESOURCE_DISPLAY_TYPE.SHARE;
			net[0].dwUsage = RESOURCE_USAGE.CONNECTABLE;
			net[0].lpLocalName = driveLetter;
			net[0].lpRemoteName = sharePath;
			Disconnect(driveLetter);
			var error = WNetAddConnection2A(net, password, user, 1);
			if (error != ERROR.SUCCESS)
				throw error.GetException();

			return driveLetter;
		}

		/// <summary/>
		public static int Disconnect(string driveLetter)
		{
			return WNetCancelConnection2A(driveLetter, 1, 1);
		}
	}

	#region WINDOWPLACEMENT

	/// <summary>
	/// 这个结构用于GetWindowPlacement和SetWindowPlacement函数以获取或设置窗口的状态及位置信息
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct WINDOWPLACEMENT
	{
		/// <summary>
		/// 表明可以指定最小化窗口的x和y坐标。如果是在ptMinPosition成员中设置坐标，则必须指定这个标志。 
		/// The ptMinPosition specifies the x,y location of the window when minimized.
		/// </summary>
		public static int WPF_SETMINPOSITION = 0x0001;
		/// <summary>
		/// 表明复原后的窗口将会被最大化，而不管它在最小化之前是否是最大化的。这个设置仅在下一次复原窗口时有效。它不改变缺省的复原操作。这个标志仅当showCmd成员中指定了SW_SHOWMINIMIZED时才有效。 
		/// The SW_SHOWMINIMIZED constant must be specified in the showCmd parameter. Indicates that the window should be maximized the next time it is restored.
		/// </summary>
		public static int WPF_RESTORETOMAXIMIZED = 0x0002;
		public static int WPF_ASYNCWINDOWPLACEMENT = 0x0004;

		private static WINDOWPLACEMENT _Empty;

		public static WINDOWPLACEMENT Empty
		{
			get
			{
				if (WINDOWPLACEMENT._Empty.Length != 44)
					WINDOWPLACEMENT._Empty.Length = 44;
				return WINDOWPLACEMENT._Empty;
			}
		}

		public static WINDOWPLACEMENT Create()
		{
			WINDOWPLACEMENT v = new WINDOWPLACEMENT();
			v.Length = 44;
			return v;
		}

		/// <summary>
		/// 这个结构的长度（size），必须是44
		/// </summary>
		public int Length;
		/// <summary>
		/// 指定了控制最小化窗口的位置的标志以及复原窗口的方法。
		/// WPF_SETMINPOSITION
		/// WPF_RESTORETOMAXIMIZED
		/// 两个常数之一或都是
		/// </summary>
		public int flags;
		/// <summary>
		/// 指定了窗口的当前显示状态。这个成员可以是 SW 值之一
		/// Visibility flags
		/// </summary>
		public int showCmd;
		/// <summary>
		/// 指定了窗口被最小化时左上角的位置。
		/// The x,y location of the window when minimized.
		/// </summary>
		public POINT ptMinPosition;
		/// <summary>
		/// 指定了窗口被最大化时左上角的位置。
		/// The x,y location of the window location when maximized.
		/// </summary>
		public POINT ptMaxPosition;
		/// <summary>
		/// 指定了窗口处于正常状态（复原）时的坐标。
		/// The position and size of the window when it is restored (normal condition).
		/// </summary>
		public RECT rcNormalPosition;
	}

	#endregion

	#region RANGE

	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct RANGE
	{
		private readonly static RANGE _Empty;

		public static RANGE Empty
		{
			get
			{
				return RANGE._Empty;
			}
		}

		public int From;
		public int To;

		public int Start
		{
			set
			{
				this.From = value;
			}
			get
			{
				return this.From;
			}
		}

		public int End
		{
			set
			{
				this.To = value;
			}
			get
			{
				return this.To;
			}
		}
	}

	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct RANGE64
	{
		private readonly static RANGE64 _Empty;

		public static RANGE64 Empty
		{
			get
			{
				return RANGE64._Empty;
			}
		}

		public long From;
		public long To;

		public long Start
		{
			set
			{
				this.From = value;
			}
			get
			{
				return this.From;
			}
		}

		public long End
		{
			set
			{
				this.To = value;
			}
			get
			{
				return this.To;
			}
		}
	}

	#endregion

	#region POINT

	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct POINT
	{
		private readonly static POINT _Empty;

		public static POINT Empty
		{
			get
			{
				return POINT._Empty;
			}
		}

		public int X;
		public int Y;
	}

	#endregion

	#region SIZE

	/// <summary>
	/// 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct SIZE
	{
		private readonly static SIZE _Empty;

		public static SIZE Empty
		{
			get
			{
				return SIZE._Empty;
			}
		}

		public int Width;
		public int Height;
	}

	#endregion

	#region RECT

	/// <summary>
	/// 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct RECT
	{
		private readonly static RECT _Empty;

		public static RECT Empty
		{
			get
			{
				return RECT._Empty;
			}
		}

		public int Left;
		public int Top;
		public int Right;
		public int Bottom;

		public POINT Point
		{
			get
			{
				var p = new POINT();
				p.X = this.Left;
				p.Y = this.Top;
				return p;
			}
		}

		public SIZE Size
		{
			get
			{
				var s = new SIZE();
				s.Width = this.Width;
				s.Height = this.Height;
				return s;
			}
		}

		public int X
		{
			set
			{
				this.Left = value;
			}
			get
			{
				return this.Left;
			}
		}

		public int Y
		{
			set
			{
				this.Top = value;
			}
			get
			{
				return this.Top;
			}
		}

		public int Width
		{
			get
			{
				return this.Right - this.Left;
			}
		}

		public int Height
		{
			get
			{
				return this.Bottom - this.Top;
			}
		}

		public override string ToString()
		{
			return base.ToString() + string.Format(" Left:{0} Top:{1} Right: {2} Bottom: {3} Width: {4} Height: {5}", this.Left, this.Top, this.Right, this.Bottom, this.Width, this.Height);
			//return base.ToString();
		}
	}

	#endregion

	#region MouseEventFlag

	[Flags]
	[ComVisible(true)]
	public enum MouseEventFlag : uint
	{
		Move = 0x0001,
		LeftDown = 0x0002,
		LeftUp = 0x0004,
		RightDown = 0x0008,
		RightUp = 0x0010,
		MiddleDown = 0x0020,
		MiddleUp = 0x0040,
		XDown = 0x0080,
		XUp = 0x0100,
		Wheel = 0x0800,
		VirtualDesk = 0x4000,
		Absolute = 0x8000
	}

	#endregion

	#region WIN32_FIND_DATA

	/// <summary>
	/// 
	/// </summary>
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	public struct WIN32_FIND_DATA
	{
		public int dwFileAttributes;
		public FILETIME_INFO ftCreationTime;
		public FILETIME_INFO ftLastAccessTime;
		public FILETIME_INFO ftLastWriteTime;
		public int nFileSizeHigh;
		public int nFileSizeLow;
		/// <summary>
		/// If the dwFileAttributes member includes the FILE_ATTRIBUTE_REPARSE_POINT attribute, this member specifies the reparse point tag. Otherwise, this value is undefined and should not be used.
		/// </summary>
		public int dwReserved0;
		/// <summary>
		/// Reserved for future use.
		/// </summary>
		public int dwReserved1;
		/// <summary>
		/// The name of the file.
		/// </summary>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
		public string cFileName;
		/// <summary>
		/// An alternative name for the file.This name is in the classic 8.3 file name format.
		/// </summary>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
		public string cAlternateFileName;

		private const int MAX_PATH = 256;//260
	}

	#endregion

	#region BY_HANDLE_FILE_INFORMATION

	public struct BY_HANDLE_FILE_INFORMATION
	{
		/// <summary>
		/// File attributes. The following table shows the possible values for dwFileAttributes.
		/// </summary>
		//[DisplayName("FileAttributes")]
		public uint dwFileAttributes;
		/// <summary>
		/// Time the file was created. If the underlying file system does not support this time member, ftCreationTime is zero.
		/// </summary>
		//[DisplayName("CreationTime")]
		public FILETIME_INFO ftCreationTime;
		/// <summary>
		/// Time the file was last accessed. If the underlying file system does not support this time member, ftLastAccessTime is zero.
		/// </summary>
		//[DisplayName("LastAccessTime")]
		public FILETIME_INFO ftLastAccessTime;
		/// <summary>
		/// Last time the file was written to.
		/// </summary>
		//[DisplayName("LastWriteTime")]
		public FILETIME_INFO ftLastWriteTime;
		/// <summary>
		/// Serial number of the volume that contains the file.
		/// </summary>
		//[DisplayName("VolumeSerialNumber")]
		public uint dwVolumeSerialNumber;
		/// <summary>
		/// High-order word of the file size.
		/// </summary>
		//[DisplayName("FileSizeHigh")]
		public uint nFileSizeHigh;
		/// <summary>
		/// Low-order word of the file size.
		/// </summary>
		//[DisplayName("FileSizeLow")]
		public uint nFileSizeLow;
		/// <summary>
		/// Number of links to this file. For the FAT file system this member is always 1.
		/// </summary>
		//[DisplayName("NumberOfLinks")]
		public uint nNumberOfLinks;
		/// <summary>
		/// High-order word of a unique identifier associated with the file.
		/// </summary>
		//[DisplayName("FileIndexHigh")]
		public uint nFileIndexHigh;
		/// <summary>
		/// Low-order word of a unique identifier associated with the file. This identifier and the volume serial number uniquely identify a file. This number may change when the system is restarted or when the file is opened. After a process opens a file, the identifier is constant until the file is closed. An application can use this identifier and the volume serial number to determine whether two handles refer to the same file.
		/// </summary>
		//[DisplayName("FileIndexLow")]
		public uint nFileIndexLow;
		/// <summary>
		/// Object identifier of the file. This parameter is only valid on files that are stored in the object store. Files on external file systems do not have object identifiers associated with them.
		/// </summary>
		//[DisplayName("OID")]
		public uint dwOID;
	}

	#endregion

	#region CPU_INFO

	/// <summary>
	/// 定义CPU的信息结构
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct CPU_INFO
	{
		public uint dwOemId;
		public uint dwPageSize;
		public uint lpMinimumApplicationAddress;
		public uint lpMaximumApplicationAddress;
		public uint dwActiveProcessorMask;
		public uint dwNumberOfProcessors;
		public uint dwProcessorType;
		public uint dwAllocationGranularity;
		public uint dwProcessorLevel;
		public uint dwProcessorRevision;
	}

	#endregion

	#region MEMORY_INFO

	/// <summary>
	/// 定义内存的信息结构
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct MEMORY_INFO
	{
		public uint dwLength;
		public uint dwMemoryLoad;
		public uint dwTotalPhys;
		public uint dwAvailPhys;
		public uint dwTotalPageFile;
		public uint dwAvailPageFile;
		public uint dwTotalVirtual;
		public uint dwAvailVirtual;
	}

	#endregion

	#region FILETIME_INFO

	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0)]
	public struct FILETIME_INFO
	{
		public uint dwLowDateTime;
		public uint dwHighDateTime;

		public SYSTEMTIME_INFO GetSYSTEMTIME()
		{
			var s = new SYSTEMTIME_INFO();
			var l = Kernel32.FileTimeToSystemTime(ref this, ref s);
			return s;
		}

		public DateTime GetDateTime()
		{
			var s = new SYSTEMTIME_INFO();
			var l = Kernel32.FileTimeToSystemTime(ref this, ref s);
			return s.GetDateTime();
		}
	}

	#endregion

	#region SYSTEMTIME_INFO

	/// <summary>
	/// 定义系统时间的信息结构
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct SYSTEMTIME_INFO
	{
		public ushort wYear;
		public ushort wMonth;
		public ushort wDayOfWeek;
		public ushort wDay;
		public ushort wHour;
		public ushort wMinute;
		public ushort wSecond;
		public ushort wMilliseconds;

		public DateTime GetDateTime()
		{
			return new DateTime(this.wYear, this.wMonth, this.wDay, this.wHour, this.wMinute, this.wSecond, this.wMilliseconds, DateTimeKind.Utc);
		}
	}

	#endregion

	#region GetVersionOutParams

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct GetVersionOutParams
	{
		public byte bVersion;
		public byte bRevision;
		public byte bReserved;
		public byte bIDEDeviceMap;
		public uint fCapabilities;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
		public uint[] dwReserved; // For future use.
	}

	#endregion

	#region IdeRegs

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct IdeRegs
	{
		public byte bFeaturesReg;
		public byte bSectorCountReg;
		public byte bSectorNumberReg;
		public byte bCylLowReg;
		public byte bCylHighReg;
		public byte bDriveHeadReg;
		public byte bCommandReg;
		public byte bReserved;
	}

	#endregion

	#region SendCmdInParams

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct SendCmdInParams
	{
		public uint cBufferSize;
		public IdeRegs irDriveRegs;
		public byte bDriveNumber;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
		public byte[] bReserved;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
		public uint[] dwReserved;
		public byte bBuffer;
	}

	#endregion

	#region SendCmdOutParams

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct SendCmdOutParams
	{
		public uint cBufferSize;
		public DriverStatus DriverStatus;
		public IdSector bBuffer;
	}

	#endregion

	#region DriverStatus

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct DriverStatus
	{
		public byte bDriverError;
		public byte bIDEStatus;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
		public byte[] bReserved;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
		public uint[] dwReserved;
	}

	#endregion

	#region IdSector

	[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 512)]
	public struct IdSector
	{
		public ushort wGenConfig;
		public ushort wNumCyls;
		public ushort wReserved;
		public ushort wNumHeads;
		public ushort wBytesPerTrack;
		public ushort wBytesPerSector;
		public ushort wSectorsPerTrack;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
		public ushort[] wVendorUnique;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
		public byte[] sSerialNumber;
		public ushort wBufferType;
		public ushort wBufferSize;
		public ushort wECCSize;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
		public byte[] sFirmwareRev;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
		public byte[] sModelNumber;
		public ushort wMoreVendorUnique;
		public ushort wDoubleWordIO;
		public ushort wCapabilities;// wCapabilities / 2 / 1024
		public ushort wReserved1;
		public ushort wPIOTiming;
		public ushort wDMATiming;
		public ushort wBS;
		public ushort wNumCurrentCyls;
		public ushort wNumCurrentHeads;
		public ushort wNumCurrentSectorsPerTrack;
		public uint ulCurrentSectorCapacity;
		public ushort wMultSectorStuff;
		public uint ulTotalAddressableSectors;
		public ushort wSingleWordDMA;
		public ushort wMultiWordDMA;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
		public byte[] bReserved;

		public string SerialNumber
		{
			get
			{
				return ToString(this.sSerialNumber);
			}
		}

		public string FirmwareRev
		{
			get
			{
				return ToString(this.sFirmwareRev);
			}
		}

		public string ModelNumber
		{
			get
			{
				return ToString(this.sModelNumber);
			}
		}

		public string Reserved
		{
			get
			{
				return Encoding.ASCII.GetString(this.bReserved).Trim();
			}
		}

		public static string ToString(byte[] data)
		{
			if (data == null)
				return null;

			if (data.Length == 0)
				return string.Empty;

			for (var i = 0; i < data.Length; i += 2)
			{
				var v = data[i];
				data[i] = data[i + 1];
				data[i + 1] = v;
			}
			return Encoding.ASCII.GetString(data).Trim();
		}
	}

	#endregion

	#region BITMAPINFOHEADER

	/// <summary>
	/// 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct BITMAPINFOHEADER
	{
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biSize;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biWidth;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biHeight;
		[MarshalAs(UnmanagedType.I2)]
		public short biPlanes;
		[MarshalAs(UnmanagedType.I2)]
		public short biBitCount;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biCompression;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biSizeImage;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biXPelsPerMeter;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biYPelsPerMeter;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biClrUsed;
		[MarshalAs(UnmanagedType.I4)]
		public Int32 biClrImportant;
	}

	#endregion

	#region BITMAPINFO

	/// <summary>
	/// 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct BITMAPINFO
	{
		[MarshalAs(UnmanagedType.Struct, SizeConst = 40)]
		public BITMAPINFOHEADER bmiHeader;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
		public int[] bmiColors;
	}

	#endregion

	#region SHFILEINFO

	[StructLayout(LayoutKind.Sequential)]
	public struct SHFILEINFO
	{
		public IntPtr hIcon;
		public IntPtr iIcon;
		public uint dwAttributes;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
		public string szDisplayName;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
		public string szTypeName;
	}

	#endregion

	#region VIDEOHDR

	/// <summary>
	/// 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct VIDEOHDR
	{
		[MarshalAs(UnmanagedType.I4)]
		public int lpData;
		[MarshalAs(UnmanagedType.I4)]
		public int dwBufferLength;
		[MarshalAs(UnmanagedType.I4)]
		public int dwBytesUsed;
		[MarshalAs(UnmanagedType.I4)]
		public int dwTimeCaptured;
		[MarshalAs(UnmanagedType.I4)]
		public int dwUser;
		[MarshalAs(UnmanagedType.I4)]
		public int dwFlags;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
		public int[] dwReserved;
	}

	#endregion

	#region KeyModifiers

	/// <summary>
	/// 组合键枚举
	/// </summary>
	[Flags]
	[ComVisible(true)]
	public enum KeyModifiers
	{
		/// <summary>
		/// 0x0000
		/// </summary>
		None = 0x0000,
		/// <summary>
		/// 0x0001
		/// </summary>
		Alt = 0x0001,
		/// <summary>
		/// 0x0002
		/// </summary>
		Control = 0x0002,
		/// <summary>
		/// 0x0004
		/// </summary>
		Shift = 0x0004,
		/// <summary>
		/// 0x0008
		/// </summary>
		Windows = 0x0008,
		/// <summary>
		/// 0x4000
		/// </summary>
		NoRepeat = 0x4000,
	}

	#endregion

	#region PropSpec

	/// <summary>
	/// PropSpec [IPropertySetStorage] 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Explicit, Size = 8, CharSet = CharSet.Unicode)]
	public struct PropSpec
	{
		/// <summary>
		/// PRSPEC_LPWSTR:0;PRSPEC_PROPID:1;
		/// </summary>
		[FieldOffset(0)]
		public int ulKind;
		[FieldOffset(4)]
		public IntPtr Name_Or_ID;
	}

	#endregion

	#region PropVariant

	/// <summary>
	/// PropVariant [IPropertySetStorage] 
	/// </summary>
	[ComVisible(true)]
	[StructLayout(LayoutKind.Explicit, Size = 16)]
	public struct PropVariant
	{
		[FieldOffset(0)]
		public short variantType;
		[FieldOffset(8)]
		public IntPtr pointerValue;
		[FieldOffset(8)]
		public byte byteValue;
		[FieldOffset(8)]
		public long longValue;

		public void FromObject(object obj)
		{
			if (obj.GetType() == typeof(string))
			{
				this.variantType = (short)VarEnum.VT_LPWSTR;
				this.pointerValue = Marshal.StringToHGlobalUni((string)obj);
			}
		}

		public object ToObject()
		{
			switch ((VarEnum)this.variantType)
			{
				case VarEnum.VT_BSTR:
					return Marshal.PtrToStringBSTR(this.pointerValue);
				//Marshal.FreeCoTaskMem(this.pointerValue);
				case VarEnum.VT_UI1:
					return this.byteValue;
				case VarEnum.VT_UI2:
					return (short)this.longValue;
				case VarEnum.VT_I4:
					return (int)this.pointerValue;
				case VarEnum.VT_UI8:
					return this.longValue;
				case VarEnum.VT_INT:
					return (short)this.longValue;
				case VarEnum.VT_LPSTR:
					return Marshal.PtrToStringAnsi(this.pointerValue);
				//Marshal.FreeCoTaskMem(this.pointerValue);
				case VarEnum.VT_LPWSTR:
					return Marshal.PtrToStringUni(this.pointerValue);
				//Marshal.FreeCoTaskMem(ptr);
				case VarEnum.VT_FILETIME:
					return DateTime.FromFileTime(this.longValue);
				case VarEnum.VT_BOOL:
					return (this.byteValue == 0 ? false : true);
				case VarEnum.VT_NULL:
				case VarEnum.VT_EMPTY:
					return null;
				default:
					throw new ArgumentException(String.Format("Unsupported variant type {0}", this.variantType));
			}
			return null;
		}
	}

	#endregion

	#region STATPROPSTG

	[ComVisible(true)]
	[StructLayout(LayoutKind.Sequential)]
	public struct STATPROPSTG
	{
		public IntPtr lpwstrName;
		public int propid;
		public short vt;
	}

	#endregion

	#region IPropertySetStorage

	/// <summary>
	/// IPropertySetStorage [StgCreateStorageEx | StgOpenStorageEx]
	/// </summary>
	[ComImport]
	[ComVisible(true)]
	[Guid(FileSummary.IID_PropertySetStorage)]
	[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
	public interface IPropertySetStorage
	{
		/// <summary>
		/// Creates a new property set.
		/// </summary>
		/// <param name="rfmtid"></param>
		/// <param name="pclsid"></param>
		/// <param name="grfFlags"></param>
		/// <param name="grfMode"></param>
		/// <param name="propertyStorage"></param>
		/// <returns></returns>
		uint Create([In, MarshalAs(UnmanagedType.Struct)] ref Guid rfmtid, [In] IntPtr pclsid, [In] int grfFlags, [In] int grfMode, ref IPropertyStorage propertyStorage);

		/// <summary>
		/// Opens a previously created property set.
		/// </summary>
		/// <param name="rfmtid"></param>
		/// <param name="grfMode"></param>
		/// <param name="propertyStorage"></param>
		/// <returns></returns>
		uint Open([In, MarshalAs(UnmanagedType.Struct)] ref Guid rfmtid, [In] int grfMode, [Out] out IPropertyStorage propertyStorage);

		/// <summary>
		/// Deletes an existing property set.
		/// </summary>
		/// <param name="rfmtid"></param>
		/// <returns></returns>
		uint Delete([In, MarshalAs(UnmanagedType.Struct)] ref Guid rfmtid);
	}

	#endregion

	#region IPropertyStorage

	/// <summary>
	/// IPropertyStorage [IPropertySetStorage]
	/// </summary>
	[ComImport]
	[ComVisible(true)]
	[Guid(FileSummary.IID_PropertyStorage)]
	[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
	public interface IPropertyStorage
	{
		/// <summary>
		/// 
		/// </summary>
		/// <param name="numProperties"></param>
		/// <param name="propertySpecifications"></param>
		/// <param name="propertyValues"></param>
		/// <returns></returns>
		/// <!-- LPArray、ByValArray 或 SafeArray -->
		uint ReadMultiple([In] uint numProperties,
			[In, Out, MarshalAs(UnmanagedType.Struct)] ref PropSpec propertySpecifications,
			[In, Out, MarshalAs(UnmanagedType.Struct)] ref PropVariant propertyValues);
		//uint ReadMultiple([In] uint numProperties,
		//    [In, MarshalAs(UnmanagedType.SafeArray, SafeArrayUserDefinedSubType=typeof(PropSpec))] PropSpec[] propertySpecifications,
		//    [Out, MarshalAs(UnmanagedType.SafeArray, SafeArrayUserDefinedSubType = typeof(PropVariant))] PropVariant[] propertyValues);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="numProperties"></param>
		/// <param name="propertySpecification"></param>
		/// <param name="propertyValues"></param>
		/// <param name="propIDNameFirst"></param>
		/// <returns></returns>
		uint WriteMultiple([In] uint numProperties, [MarshalAs(UnmanagedType.Struct)] ref PropSpec propertySpecification, ref PropVariant propertyValues, int propIDNameFirst);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="cpropid">The size on input of the array rgpropid. Can be zero. However, making it zero causes this method to become non-operational.</param>
		/// <param name="rgpropid">An array of the property IDs for which names are to be set.</param>
		/// <param name="rglpwstrName">An array of new names to be assigned to the corresponding property IDs in the rgpropid array. These names may not exceed 255 characters (not including the NULL terminator).</param>
		/// <returns></returns>
		uint WritePropertyNames([In] uint cpropid, [In] uint[] rgpropid, [In]  string[] rglpwstrName);

		/// <summary>
		/// 
		/// </summary>
		/// <param name="ppEnum"></param>
		//void Enum([Out, MarshalAs(UnmanagedType.Interface)] out IEnumSTATPROPSTG ppEnum);
		void Enum([In, Out]ref IEnumSTATPROPSTG ppEnum);

		/// <summary/>
		uint Commit(int commitFlags);
	}

	#endregion

	#region IEnumSTATPROPSTG

	[ComImport]
	[ComVisible(true)]
	[Guid(FileSummary.IID_EnumSTATPROPSTG)]
	[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
	public interface IEnumSTATPROPSTG
	{
		void Clone([Out] out IEnumSTATPROPSTG ppEnum);
		[PreserveSig]
		int Next([In] uint celt, [Out] out STATPROPSTG[] rgelt, [Out] out uint pceltFetched);
		int Reset();
		int Skip([In] uint celt);
	}

	#endregion

	#region OFSTRUCT

	/// <summary>
	/// 
	/// </summary>
	[StructLayout(LayoutKind.Sequential)]
	public struct OFSTRUCT
	{
		/// <summary>
		/// The size of the structure, in bytes.
		/// </summary>
		public byte cBytes;
		/// <summary>
		/// If this member is nonzero, the file is on a hard (fixed) disk. Otherwise, it is not.
		/// </summary>
		public byte fFixedDisk;
		/// <summary>
		/// The MS-DOS error code if the OpenFile function failed.
		/// </summary>
		public int nErrCode;
		/// <summary>
		/// Reserved; do not use.
		/// </summary>
		public int Reserved1;
		/// <summary>
		/// Reserved; do not use.
		/// </summary>
		public int Reserved2;
		/// <summary>
		/// The path and file name of the file.
		/// </summary>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = byte.MaxValue)]
		public string szPathName;
	}

	/// <summary>
	/// 
	/// </summary>
	public enum OF : int
	{
		/// <summary>
		/// Ignored.
		/// To produce a dialog box containing a Cancel button, use OF_PROMPT.
		/// </summary>
		Cancel = 0x00000800,
		/// <summary>
		/// Creates a new file.
		/// If the file exists, it is truncated to zero (0) length.
		/// </summary>
		Create = 0x00001000,
		/// <summary>
		/// Deletes a file.
		/// </summary>
		Delete = 0x00000200,
		/// <summary>
		/// Opens a file and then closes it.
		/// Use this to test for the existence of a file.
		/// </summary>
		Exist = 0x00004000,
		/// <summary>
		/// Fills the OFSTRUCT structure, but does not do anything else.
		/// </summary>
		Parse = 0x00000100,
		/// <summary>
		/// Displays a dialog box if a requested file does not exist.
		/// A dialog box informs a user that the system cannot find a file, and it contains Retry and Cancel buttons. The Cancel button directs OpenFile to return a file-not-found error message.
		/// </summary>
		Prompt = 0x00002000,
		/// <summary>
		/// Opens a file for reading only.
		/// </summary>
		Read = 0x00000000,
		/// <summary>
		/// Opens a file with read/write permissions.
		/// </summary>
		ReadWrite = 0x00000002,
		/// <summary>
		/// Opens a file by using information in the reopen buffer.
		/// </summary>
		Reopen = 0x00008000,
		/// <summary>
		/// For MS-DOS–based file systems, opens a file with compatibility mode, allows any process on a specified computer to open the file any number of times.
		/// Other efforts to open a file with other sharing modes fail. This flag is mapped to the FILE_SHARE_READ|FILE_SHARE_WRITE flags of the CreateFile function.
		/// </summary>
		ShareCompat = 0x00000000,
		/// <summary>
		/// Opens a file without denying read or write access to other processes.
		/// On MS-DOS-based file systems, if the file has been opened in compatibility mode by any other process, the function fails.
		/// This flag is mapped to the FILE_SHARE_READ|FILE_SHARE_WRITE flags of the CreateFile function.
		/// </summary>
		ShareDenyNone = 0x00000040,
		/// <summary>
		/// Opens a file and denies read access to other processes.
		/// On MS-DOS-based file systems, if the file has been opened in compatibility mode, or for read access by any other process, the function fails.
		/// This flag is mapped to the FILE_SHARE_WRITE flag of the CreateFile function.
		/// </summary>
		ShareDenyRead = 0x00000030,
		/// <summary>
		/// Opens a file and denies write access to other processes.
		/// On MS-DOS-based file systems, if a file has been opened in compatibility mode, or for write access by any other process, the function fails.
		/// This flag is mapped to the FILE_SHARE_READ flag of the CreateFile function.
		/// </summary>
		ShareDenyWrite = 0x00000020,
		/// <summary>
		/// Opens a file with exclusive mode, and denies both read/write access to other processes. If a file has been opened in any other mode for read/write access, even by the current process, the function fails.
		/// </summary>
		ShareExclusive = 0x00000010,
		/// <summary>
		/// Verifies that the date and time of a file are the same as when it was opened previously.
		/// This is useful as an extra check for read-only files.
		/// </summary>
		Verify = -1,
		/// <summary>
		/// Opens a file for write access only.
		/// </summary>
		Write = 0x00000001,
	}

	#endregion

	#region ReparseTagType

	/// <summary>
	/// 
	/// </summary>
	public enum ReparseTagType : uint
	{
		/// <summary>
		/// IO_REPARSE_TAG_MOUNT_POINT
		/// </summary>
		MountPoint = IO_REPARSE_TAG.MOUNT_POINT,        // Moiunt point or junction, see winnt.h
														/// <summary>
														/// IO_REPARSE_TAG_HSM
														/// </summary>
		HSM = IO_REPARSE_TAG.HSM,
		/// <summary>
		/// IO_REPARSE_TAG_SIS
		/// </summary>
		SIS = IO_REPARSE_TAG.SIS,
		/// <summary>
		/// IO_REPARSE_TAG_DFS
		/// </summary>
		DFS = IO_REPARSE_TAG.DFS,
		/// <summary>
		/// IO_REPARSE_TAG_SYMLINK
		/// </summary>
		Symlink = IO_REPARSE_TAG.SYMLINK,           // SYMLINK or SYMLINKD (see http://wesnerm.blogs.com/net_undocumented/2006/10/index.html)
													/// <summary>
													/// IO_REPARSE_TAG_DFSR
													/// </summary>
		DFSR = IO_REPARSE_TAG.DFSR,
	}

	#endregion

	#region REPARSE_DATA_BUFFER

	// This is the official version of the data buffer, see http://msdn2.microsoft.com/en-us/library/ms791514.aspx
	// not the one used at http://www.flexhex.com/docs/articles/hard-links.phtml
	/// <summary>
	/// 
	/// </summary>
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
	public struct REPARSE_DATA_BUFFER// max length = 16KB.
	{
		public const string PATH_PREFIX = @"\??\";
		/// <summary>
		/// 
		/// </summary>
		public const int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024;

		public REPARSE_DATA_BUFFER(ReparseTagType reparseTag)
		{
			this.ReparseTag = reparseTag;
			this.ReparseDataLength = (ushort)Marshal.SizeOf(typeof(REPARSE_DATA_BUFFER));// MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
			this.Reserved = 0;
			this.SubstituteNameOffset = 0;
			this.SubstituteNameLength = 0;
			this.PrintNameOffset = 0;
			this.PrintNameLength = 0;
			this.DataBuffer = new byte[MAXIMUM_REPARSE_DATA_BUFFER_SIZE - 16];
		}

		public REPARSE_DATA_BUFFER(IntPtr p) : this(ReparseTagType.MountPoint)
		{
			if (p == IntPtr.Zero)
				return;

			this.SetPrt(p);
		}

		public IntPtr GetPtr()
		{
			var size = Marshal.SizeOf(this);
			var buffer = Marshal.AllocHGlobal(size);
			Marshal.StructureToPtr(this, buffer, false);
			return buffer;
		}

		public void SetPrt(IntPtr p)
		{
			this.DataBuffer = new byte[MAXIMUM_REPARSE_DATA_BUFFER_SIZE - 16];
			if (p == IntPtr.Zero)
				return;

			try
			{
				Marshal.PtrToStructure(p, this);
				return;
			}
			catch// (Exception x)
			{
				//
			}

			var @this = (REPARSE_DATA_BUFFER)Marshal.PtrToStructure(p, this.GetType());
			this.ReparseTag = @this.ReparseTag;
			this.ReparseDataLength = @this.ReparseDataLength;
			this.Reserved = @this.Reserved;
			this.SubstituteNameOffset = @this.SubstituteNameOffset;
			this.SubstituteNameLength = @this.SubstituteNameLength;
			this.PrintNameOffset = @this.PrintNameOffset;
			this.PrintNameLength = @this.PrintNameLength;
			this.DataBuffer = @this.DataBuffer;
		}

		public string SubstituteName
		{
			set
			{
				var bs = Encoding.Unicode.GetBytes(PATH_PREFIX + Path.GetFullPath(value));
				if (this.DataBuffer != null && this.DataBuffer.Length > bs.Length)
				{
					this.SubstituteNameOffset = 0;
					this.SubstituteNameLength = (ushort)bs.Length;
					var ds = new byte[this.PrintNameLength];
					if (this.PrintNameLength > 0)
						Array.Copy(this.DataBuffer, this.PrintNameOffset, ds, 0, this.PrintNameLength);
					this.PrintNameOffset = (ushort)(this.SubstituteNameLength + 2);
					Array.Copy(bs, 0, this.DataBuffer, this.SubstituteNameOffset, this.SubstituteNameLength);
					if (this.PrintNameLength > 0)
						Array.Copy(ds, 0, this.DataBuffer, this.PrintNameOffset, this.PrintNameLength);
					this.ReparseDataLength = (ushort)Marshal.SizeOf(this);
					return;
				}

				this.DataBuffer = bs;
				this.ReparseDataLength = (ushort)Marshal.SizeOf(this);
			}
			get
			{
				if (this.SubstituteNameLength > 0)
				{
					if (this.ReparseTag == ReparseTagType.Symlink)
						return Encoding.Unicode.GetString(this.DataBuffer, this.SubstituteNameOffset + Encoding.Unicode.GetByteCount("\0\0"), this.SubstituteNameLength);

					return Encoding.Unicode.GetString(this.DataBuffer, this.SubstituteNameOffset, this.SubstituteNameLength);
				}

				return string.Empty;
			}
		}

		public string PrintName
		{
			set
			{
				var bs = Encoding.Unicode.GetBytes(PATH_PREFIX + Path.GetFullPath(value));
				if (this.SubstituteNameOffset > 0 && this.SubstituteNameLength > 0)
					this.PrintNameOffset = (ushort)(this.SubstituteNameOffset + this.SubstituteNameLength + 2);
				else
					this.PrintNameOffset = 0;
				this.PrintNameLength = (ushort)bs.Length;
				if (this.DataBuffer != null && this.DataBuffer.Length > bs.Length)
				{
					if (this.DataBuffer.Length >= this.PrintNameOffset + this.PrintNameLength)
					{
						Array.Copy(bs, 0, this.DataBuffer, this.PrintNameOffset, this.PrintNameLength);
						this.ReparseDataLength = (ushort)Marshal.SizeOf(this);
						return;
					}

					var ds = new byte[this.PrintNameOffset + this.PrintNameLength];
					if (this.SubstituteNameOffset + this.SubstituteNameLength > 0)
						Array.Copy(this.DataBuffer, 0, ds, 0, this.DataBuffer.Length);
					Array.Copy(bs, 0, ds, this.PrintNameOffset, this.PrintNameLength);
					this.DataBuffer = ds;
					this.ReparseDataLength = (ushort)Marshal.SizeOf(this);
					return;
				}

				this.DataBuffer = bs;
				this.ReparseDataLength = (ushort)Marshal.SizeOf(this);
			}
			get
			{
				if (this.PrintNameLength > 0)
				{
					if (this.ReparseTag == ReparseTagType.Symlink)
						return Encoding.Unicode.GetString(this.DataBuffer, this.PrintNameOffset + Encoding.Unicode.GetByteCount("\0\0"), this.PrintNameLength);

					return Encoding.Unicode.GetString(this.DataBuffer, this.PrintNameOffset, this.PrintNameLength);
				}

				return string.Empty;
			}
		}

		/// <summary>
		/// Reparse point tag. Must be a Microsoft reparse point tag.
		/// </summary>
		[MarshalAs(UnmanagedType.U4)]
		public ReparseTagType ReparseTag;
		/// <summary>
		/// Size, in bytes, of the data after the Reserved member. This can be calculated by:
		/// (4 * sizeof(ushort)) + SubstituteNameLength + PrintNameLength + (namesAreNullTerminated ? 2 * sizeof(char) : 0);
		/// </summary>
		[MarshalAs(UnmanagedType.U2)]
		public ushort ReparseDataLength;
		/// <summary>
		/// Reserved; do not use.
		/// </summary>
		[MarshalAs(UnmanagedType.U2)]
		public ushort Reserved;
		/// <summary>
		/// Offset, in bytes, of the substitute name string in the PathBuffer array.
		/// </summary>
		[MarshalAs(UnmanagedType.U2)]
		public ushort SubstituteNameOffset;
		/// <summary>
		/// Length, in bytes, of the substitute name string. If this string is null-terminated,SubstituteNameLength does not include space for the null character.
		/// </summary>
		[MarshalAs(UnmanagedType.U2)]
		public ushort SubstituteNameLength;
		/// <summary>
		/// Offset, in bytes, of the print name string in the PathBuffer array.
		/// </summary>
		[MarshalAs(UnmanagedType.U2)]
		public ushort PrintNameOffset;
		/// <summary>
		/// Length, in bytes, of the print name string. If this string is null-terminated,PrintNameLength does not include space for the null character.
		/// </summary>
		[MarshalAs(UnmanagedType.U2)]
		public ushort PrintNameLength;
		/// <summary>
		/// A buffer containing the unicode-encoded path string. The path string contains the substitute name string and print name string.
		/// </summary>
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXIMUM_REPARSE_DATA_BUFFER_SIZE - 16)]
		public byte[] DataBuffer;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="hDevice"></param>
		/// <param name="dwIoControlCode"></param>
		/// <param name="pBytesReturned"></param>
		/// <returns></returns>
		public bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, out int pBytesReturned)
		{
			var s = (ushort)Marshal.SizeOf(this);
			var h = Marshal.AllocHGlobal(s);
			if (this.PrintNameLength > 0)
				this.ReparseDataLength = (ushort)(this.PrintNameLength + this.PrintNameOffset + 12);
			else if (this.SubstituteNameLength > 0)
				this.ReparseDataLength = (ushort)(this.SubstituteNameLength + this.SubstituteNameOffset + 12);
			else
				this.ReparseDataLength = 0;
			var b = true;
			Marshal.StructureToPtr(this, h, b);
			dwIoControlCode = FSCTL.GetCode(dwIoControlCode);
			if (dwIoControlCode == FSCTL.GetReparsePoint)
				b = Kernel32.DeviceIoControl(hDevice, dwIoControlCode, IntPtr.Zero, 0, h, s, out pBytesReturned, IntPtr.Zero);
			else
				b = Kernel32.DeviceIoControl(hDevice, dwIoControlCode, h, this.ReparseDataLength + 8, IntPtr.Zero, 0, out pBytesReturned, IntPtr.Zero);
			if (b && pBytesReturned > 0)
				this.SetPrt(h);
			Marshal.FreeHGlobal(h);
			return b;
		}
	}

	#endregion

	#region public enum RESOURCE_SCOPE

	public enum RESOURCE_SCOPE
	{
		CONNECTED = 1,
		GLOBALNET = 2,
		REMEMBERED = 3,
		RECENT = 4,
		CONTEXT = 5
	}

	#endregion

	#region public enum RESOURCE_TYPE

	public enum RESOURCE_TYPE
	{
		ANY = 0,
		DISK = 1,
		PRINT = 2,
		RESERVED = 8,
	}

	#endregion

	#region public enum RESOURCE_USAGE

	/// <summary/>
	[Flags]
	public enum RESOURCE_USAGE
	{
		/// <summary/>
		CONNECTABLE = 1,
		/// <summary/>
		CONTAINER = 2,
		/// <summary/>
		NOLOCALDEVICE = 4,
		/// <summary/>
		SIBLING = 8,
		/// <summary/>
		ATTACHED = 16,
		/// <summary/>
		ALL = (CONNECTABLE | CONTAINER | ATTACHED),
	}

	#endregion

	#region public enum RESOURCE_DISPLAYTYPE

	/// <summary/>
	public enum RESOURCE_DISPLAY_TYPE
	{
		/// <summary/>
		GENERIC = 0,
		/// <summary/>
		DOMAIN = 1,
		/// <summary/>
		SERVER = 2,
		/// <summary/>
		SHARE = 3,
		/// <summary/>
		FILE = 4,
		/// <summary/>
		GROUP = 5,
		/// <summary/>
		NETWORK = 6,
		/// <summary/>
		ROOT = 7,
		/// <summary/>
		SHAREADMIN = 8,
		/// <summary/>
		DIRECTORY = 9,
		/// <summary/>
		TREE = 10,
		/// <summary/>
		NDSCONTAINER = 11
	}

	#endregion

	#region NET_RESOURCE

	/// <summary/>
	[StructLayout(LayoutKind.Sequential)]
	public struct NET_RESOURCE
	{
		/// <summary/>
		public RESOURCE_SCOPE dwScope;
		/// <summary/>
		public RESOURCE_TYPE dwType;
		/// <summary/>
		public RESOURCE_DISPLAY_TYPE dwDisplayType;
		/// <summary/>
		public RESOURCE_USAGE dwUsage;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string lpLocalName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string lpRemoteName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string lpComment;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string lpProvider;
	}

	#endregion

	#region WinSpool any

	/// <summary/>
	[FlagsAttribute]
	public enum PRINTER_ENUM
	{
		/// <summary/>
		PRINTER_ENUM_DEFAULT = 0x00000001,
		/// <summary/>
		PRINTER_ENUM_LOCAL = 0x00000002,
		/// <summary/>
		PRINTER_ENUM_CONNECTIONS = 0x00000004,
		/// <summary/>
		PRINTER_ENUM_FAVORITE = 0x00000004,
		/// <summary/>
		PRINTER_ENUM_NAME = 0x00000008,
		/// <summary/>
		PRINTER_ENUM_REMOTE = 0x00000010,
		/// <summary/>
		PRINTER_ENUM_SHARED = 0x00000020,
		/// <summary/>
		PRINTER_ENUM_NETWORK = 0x00000040,
		/// <summary/>
		PRINTER_ENUM_EXPAND = 0x00004000,
		/// <summary/>
		PRINTER_ENUM_CONTAINER = 0x00008000,
		/// <summary/>
		PRINTER_ENUM_ICONMASK = 0x00ff0000,
		/// <summary/>
		PRINTER_ENUM_ICON1 = 0x00010000,
		/// <summary/>
		PRINTER_ENUM_ICON2 = 0x00020000,
		/// <summary/>
		PRINTER_ENUM_ICON3 = 0x00040000,
		/// <summary/>
		PRINTER_ENUM_ICON4 = 0x00080000,
		/// <summary/>
		PRINTER_ENUM_ICON5 = 0x00100000,
		/// <summary/>
		PRINTER_ENUM_ICON6 = 0x00200000,
		/// <summary/>
		PRINTER_ENUM_ICON7 = 0x00400000,
		/// <summary/>
		PRINTER_ENUM_ICON8 = 0x00800000,
		/// <summary/>
		PRINTER_ENUM_HIDE = 0x01000000,
	}

	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
	public struct PRINTER_INFO_1
	{
		public int flags;
		public string pDescription;
		public string pName;
		public string pComment;
	}

	/// <summary/>
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
	public struct PRINTER_INFO_2
	{
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pServerName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pPrinterName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pShareName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pPortName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pDriverName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pComment;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pLocation;
		/// <summary/>
		public IntPtr pDevMode;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pSepFile;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pPrintProcessor;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pDatatype;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPTStr)]
		public string pParameters;
		/// <summary/>
		public IntPtr pSecurityDescriptor;
		/// <summary/>
		public uint Attributes;
		/// <summary/>
		public uint Priority;
		/// <summary/>
		public uint DefaultPriority;
		/// <summary/>
		public uint StartTime;
		/// <summary/>
		public uint UntilTime;
		/// <summary/>
		public uint Status;
		/// <summary/>
		public uint cJobs;
		/// <summary/>
		public uint AveragePPM;

	}

	/// <summary/>
	public enum DMDO
	{
		/// <summary/>
		DEFAULT = 0,
		/// <summary/>
		D90 = 1,
		/// <summary/>
		D180 = 2,
		/// <summary/>
		D270 = 3,
	}

	/// <summary/>
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	public struct DEVMODE
	{
		/// <summary/>
		public const int DM_DISPLAYFREQUENCY = 0x400000;
		/// <summary/>
		public const int DM_PELSWIDTH = 0x80000;
		/// <summary/>
		public const int DM_PELSHEIGHT = 0x100000;
		/// <summary/>
		private const int CCHDEVICENAME = 32;
		/// <summary/>
		private const int CCHFORMNAME = 32;
		/// <summary/>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
		public string dmDeviceName;
		/// <summary/>
		public short dmSpecVersion;
		/// <summary/>
		public short dmDriverVersion;
		/// <summary/>
		public short dmSize;
		/// <summary/>
		public short dmDriverExtra;
		/// <summary/>
		public int dmFields;
		/// <summary/>
		public short dmOrientation;
		/// <summary/>
		public short dmPaperSize;
		/// <summary/>
		public short dmPaperLength;
		/// <summary/>
		public short dmPaperWidth;
		/// <summary/>
		public short dmScale;
		/// <summary/>
		public short dmCopies;
		/// <summary/>
		public short dmDefaultSource;
		/// <summary/>
		public short dmPrintQuality;
		/// <summary/>
		public short dmColor;
		/// <summary/>
		public short dmDuplex;
		/// <summary/>
		public short dmYResolution;
		/// <summary/>
		public short dmTTOption;
		/// <summary/>
		public short dmCollate;
		/// <summary/>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
		public string dmFormName;
		/// <summary/>
		public short dmLogPixels;
		/// <summary/>
		public int dmBitsPerPel;
		/// <summary/>
		public int dmPelsWidth;
		/// <summary/>
		public int dmPelsHeight;
		/// <summary/>
		public int dmDisplayFlags;
		/// <summary/>
		public int dmDisplayFrequency;
	}

	/// <summary/>
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	public struct PRINTER_DEFAULTS
	{
		//public const int DM_DUPLEX = 0x1000;
		//public const int DM_IN_BUFFER = 8;
		//public const int DM_OUT_BUFFER = 2;
		/// <summary/>
		public const int PRINTER_ACCESS_ADMINISTER = 0x4;
		/// <summary/>
		public const int PRINTER_ACCESS_USE = 0x8;
		/// <summary/>
		public const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
		/// <summary/>
		public const int PRINTER_EXECUTE = 0x00020008;
		/// <summary/>
		public const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
		/// <summary/>
		public const int SERVER_ACCESS_ADMINISTER = 0x00000001;
		/// <summary/>
		public const int SERVER_ACCESS_ENUMERATE = 0x00000002;
		/// <summary/>
		public const int SERVER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE);

		/// <summary/>
		public int pDatatype;//public string pDatatype;
							 /// <summary/>
		public int pDevMode;//public DEVMODE pDevMode;
							/// <summary/>
		public int DesiredAccess;
	}

	/// <summary/>
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
	public class DOCINFOA
	{
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string pDocName;
		/// <summary/>
		[MarshalAs(UnmanagedType.LPStr)]
		public string pOutputFile;
		/// <summary>
		/// RAW,XPS_PASS
		/// </summary>
		[MarshalAs(UnmanagedType.LPStr)]
		public string pDataType;
	}

	#endregion

	#region DCB

	/// <summary/>
	[StructLayout(LayoutKind.Sequential)]
	public struct DCB
	{
		/// <summary/>
		public int DCBlength;
		/// <summary/>
		public int BaudRate;
		/// <summary/>
		public int fBitFields;
		/// <summary/>
		public short wReserved;
		/// <summary/>
		public short XonLim;
		/// <summary/>
		public short XoffLim;
		/// <summary/>
		public byte ByteSize;
		/// <summary/>
		public byte Parity;
		/// <summary/>
		public byte StopBits;
		/// <summary/>
		public byte XonChar;
		/// <summary/>
		public byte XoffChar;
		/// <summary/>
		public byte ErrorChar;
		/// <summary/>
		public byte EofChar;
		/// <summary/>
		public byte EvtChar;
		/// <summary/>
		public short wReserved1;//Reserved; Do Not Use
	}

	#endregion

	#region COMMTIMEOUTS

	/// <summary/>
	[StructLayout(LayoutKind.Sequential)]
	public struct COMMTIMEOUTS
	{
		/// <summary/>
		public int ReadIntervalTimeout;
		/// <summary/>
		public int ReadTotalTimeoutMultiplier;
		/// <summary/>
		public int ReadTotalTimeoutConstant;
		/// <summary/>
		public int WriteTotalTimeoutMultiplier;
		/// <summary/>
		public int WriteTotalTimeoutConstant;
	}

	#endregion

	#region OVERLAPPED

	/// <summary/>
	[StructLayout(LayoutKind.Sequential)]
	public struct OVERLAPPED
	{
		/// <summary/>
		public int Internal;
		/// <summary/>
		public int InternalHigh;
		/// <summary/>
		public int Offset;
		/// <summary/>
		public int OffSetHigh;
		/// <summary/>
		public IntPtr hEvent;
	}

	#endregion

	#region WH

	/// <summary>
	/// 设置的钩子类型
	/// </summary>
	public static class WH
	{
		/// <summary>
		/// 设置的钩子类型
		/// </summary>
		public enum HookType : int
		{
			/// <summary>
			/// WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以监视菜单，滚动 
			/// 条，消息框，对话框消息并且发现用户使用ALT+TAB or ALT+ESC 组合键切换窗口。 
			/// WH_MSGFILTER Hook只能监视传递到菜单，滚动条，消息框的消息，以及传递到通 
			/// 过安装了Hook子过程的应用程序建立的对话框的消息。WH_SYSMSGFILTER Hook 
			/// 监视所有应用程序消息。 
			/// 
			/// WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以在模式循环期间 
			/// 过滤消息，这等价于在主消息循环中过滤消息。 
			///    
			/// 通过调用CallMsgFilter function可以直接的调用WH_MSGFILTER Hook。通过使用这 
			/// 个函数，应用程序能够在模式循环期间使用相同的代码去过滤消息，如同在主消息循 
			/// 环里一样
			/// </summary>
			MSGFILTER = WH.SYSMSGFILTER,
			/// <summary>
			/// WH_JOURNALRECORD Hook用来监视和记录输入事件。典型的，可以使用这 
			/// 个Hook记录连续的鼠标和键盘事件，然后通过使用WH_JOURNALPLAYBACK Hook 
			/// 来回放。WH_JOURNALRECORD Hook是全局Hook，它不能象线程特定Hook一样 
			/// 使用。WH_JOURNALRECORD是system-wide local hooks，它们不会被注射到任何行 
			/// 程地址空间
			/// </summary>
			JOURNALRECORD = WH.JOURNALRECORD,
			/// <summary>
			/// WH_JOURNALPLAYBACK Hook使应用程序可以插入消息到系统消息队列。可 
			/// 以使用这个Hook回放通过使用WH_JOURNALRECORD Hook记录下来的连续的鼠 
			/// 标和键盘事件。只要WH_JOURNALPLAYBACK Hook已经安装，正常的鼠标和键盘 
			/// 事件就是无效的。WH_JOURNALPLAYBACK Hook是全局Hook，它不能象线程特定 
			/// Hook一样使用。WH_JOURNALPLAYBACK Hook返回超时值，这个值告诉系统在处 
			/// 理来自回放Hook当前消息之前需要等待多长时间（毫秒）。这就使Hook可以控制实 
			/// 时事件的回放。WH_JOURNALPLAYBACK是system-wide local hooks，它们不会被 
			/// 注射到任何行程地址空间
			/// </summary>
			JOURNALPLAYBACK = WH.JOURNALPLAYBACK,
			/// <summary>
			/// 在应用程序中，WH_KEYBOARD Hook用来监视WM_KEYDOWN and  
			/// WM_KEYUP消息，这些消息通过GetMessage or PeekMessage function返回。可以使 
			/// 用这个Hook来监视输入到消息队列中的键盘消息
			/// </summary>
			KEYBOARD = WH.KEYBOARD,
			/// <summary>
			/// 应用程序使用WH_GETMESSAGE Hook来监视从GetMessage or PeekMessage函 
			/// 数返回的消息。你可以使用WH_GETMESSAGE Hook去监视鼠标和键盘输入，以及 
			/// 其它发送到消息队列中的消息
			/// </summary>
			WH_GETMESSAGE = WH.GETMESSAGE,
			/// <summary>
			/// 监视发送到窗口过程的消息，系统在消息发送到接收窗口过程之前调用
			/// </summary>
			CALLWNDPROC = WH.CALLWNDPROC,
			/// <summary>
			/// 在以下事件之前，系统都会调用WH_CBT Hook子过程，这些事件包括： 
			/// 1. 激活，建立，销毁，最小化，最大化，移动，改变尺寸等窗口事件； 
			/// 2. 完成系统指令； 
			/// 3. 来自系统消息队列中的移动鼠标，键盘事件； 
			/// 4. 设置输入焦点事件； 
			/// 5. 同步系统消息队列事件。
			/// Hook子过程的返回值确定系统是否允许或者防止这些操作中的一个
			/// </summary>
			CBT = WH.CBT,
			/// <summary>
			/// WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以监视菜单，滚动 
			/// 条，消息框，对话框消息并且发现用户使用ALT+TAB or ALT+ESC 组合键切换窗口。 
			/// WH_MSGFILTER Hook只能监视传递到菜单，滚动条，消息框的消息，以及传递到通 
			/// 过安装了Hook子过程的应用程序建立的对话框的消息。WH_SYSMSGFILTER Hook 
			/// 监视所有应用程序消息。 
			/// 
			/// WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以在模式循环期间 
			/// 过滤消息，这等价于在主消息循环中过滤消息。 
			///    
			/// 通过调用CallMsgFilter function可以直接的调用WH_MSGFILTER Hook。通过使用这 
			/// 个函数，应用程序能够在模式循环期间使用相同的代码去过滤消息，如同在主消息循 
			/// 环里一样
			/// </summary>
			SYSMSGFILTER = WH.SYSMSGFILTER,
			/// <summary>
			/// WH_MOUSE Hook监视从GetMessage 或者 PeekMessage 函数返回的鼠标消息。 
			/// 使用这个Hook监视输入到消息队列中的鼠标消息
			/// </summary>
			MOUSE = WH.MOUSE,
			/// <summary>
			/// 当调用GetMessage 或 PeekMessage 来从消息队列种查询非鼠标、键盘消息时
			/// </summary>
			HARDWARE = WH.HARDWARE,
			/// <summary>
			/// 在系统调用系统中与其它Hook关联的Hook子过程之前，系统会调用 
			/// WH_DEBUG Hook子过程。你可以使用这个Hook来决定是否允许系统调用与其它 
			/// Hook关联的Hook子过程
			/// </summary>
			DEBUG = WH.DEBUG,
			/// <summary>
			/// 外壳应用程序可以使用WH_SHELL Hook去接收重要的通知。当外壳应用程序是 
			/// 激活的并且当顶层窗口建立或者销毁时，系统调用WH_SHELL Hook子过程。 
			/// WH_SHELL 共有５钟情况： 
			/// 1. 只要有个top-level、unowned 窗口被产生、起作用、或是被摧毁； 
			/// 2. 当Taskbar需要重画某个按钮； 
			/// 3. 当系统需要显示关于Taskbar的一个程序的最小化形式； 
			/// 4. 当目前的键盘布局状态改变； 
			/// 5. 当使用者按Ctrl+Esc去执行Task Manager（或相同级别的程序）。 
			///
			/// 按照惯例，外壳应用程序都不接收WH_SHELL消息。所以，在应用程序能够接 
			/// 收WH_SHELL消息之前，应用程序必须调用SystemParametersInfo function注册它自 
			/// 己
			/// </summary>
			SHELL = WH.SHELL,
			/// <summary>
			/// 当应用程序的前台线程处于空闲状态时，可以使用WH_FOREGROUNDIDLE  
			/// Hook执行低优先级的任务。当应用程序的前台线程大概要变成空闲状态时，系统就 
			/// 会调用WH_FOREGROUNDIDLE Hook子过程
			/// </summary>
			FOREGROUNDIDLE = WH.FOREGROUNDIDLE,
			/// <summary>
			/// 监视发送到窗口过程的消息，系统在消息发送到接收窗口过程之后调用
			/// </summary>
			CALLWNDPROCRET = WH.CALLWNDPROCRET,
			/// <summary>
			/// 监视输入到线程消息队列中的键盘消息
			/// </summary>
			KEYBOARD_LL = WH.KEYBOARD_LL,
			/// <summary>
			/// 监视输入到线程消息队列中的鼠标消息
			/// </summary>
			MOUSE_LL = WH.MOUSE_LL,
		}

		/// <summary>
		/// WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以监视菜单，滚动 
		/// 条，消息框，对话框消息并且发现用户使用ALT+TAB or ALT+ESC 组合键切换窗口。 
		/// WH_MSGFILTER Hook只能监视传递到菜单，滚动条，消息框的消息，以及传递到通 
		/// 过安装了Hook子过程的应用程序建立的对话框的消息。WH_SYSMSGFILTER Hook 
		/// 监视所有应用程序消息。 
		/// 
		/// WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以在模式循环期间 
		/// 过滤消息，这等价于在主消息循环中过滤消息。 
		///    
		/// 通过调用CallMsgFilter function可以直接的调用WH_MSGFILTER Hook。通过使用这 
		/// 个函数，应用程序能够在模式循环期间使用相同的代码去过滤消息，如同在主消息循 
		/// 环里一样
		/// </summary>
		public const int MSGFILTER = -1;
		/// <summary>
		/// WH_JOURNALRECORD Hook用来监视和记录输入事件。典型的，可以使用这 
		/// 个Hook记录连续的鼠标和键盘事件，然后通过使用WH_JOURNALPLAYBACK Hook 
		/// 来回放。WH_JOURNALRECORD Hook是全局Hook，它不能象线程特定Hook一样 
		/// 使用。WH_JOURNALRECORD是system-wide local hooks，它们不会被注射到任何行 
		/// 程地址空间
		/// </summary>
		public const int JOURNALRECORD = 0;
		/// <summary>
		/// WH_JOURNALPLAYBACK Hook使应用程序可以插入消息到系统消息队列。可 
		/// 以使用这个Hook回放通过使用WH_JOURNALRECORD Hook记录下来的连续的鼠 
		/// 标和键盘事件。只要WH_JOURNALPLAYBACK Hook已经安装，正常的鼠标和键盘 
		/// 事件就是无效的。WH_JOURNALPLAYBACK Hook是全局Hook，它不能象线程特定 
		/// Hook一样使用。WH_JOURNALPLAYBACK Hook返回超时值，这个值告诉系统在处 
		/// 理来自回放Hook当前消息之前需要等待多长时间（毫秒）。这就使Hook可以控制实 
		/// 时事件的回放。WH_JOURNALPLAYBACK是system-wide local hooks，它们不会被 
		/// 注射到任何行程地址空间
		/// </summary>
		public const int JOURNALPLAYBACK = 1;
		/// <summary>
		/// 在应用程序中，WH_KEYBOARD Hook用来监视WM_KEYDOWN and  
		/// WM_KEYUP消息，这些消息通过GetMessage or PeekMessage function返回。可以使 
		/// 用这个Hook来监视输入到消息队列中的键盘消息
		/// </summary>
		public const int KEYBOARD = 2;
		/// <summary>
		/// 应用程序使用WH_GETMESSAGE Hook来监视从GetMessage or PeekMessage函 
		/// 数返回的消息。你可以使用WH_GETMESSAGE Hook去监视鼠标和键盘输入，以及 
		/// 其它发送到消息队列中的消息
		/// </summary>
		public const int GETMESSAGE = 3;
		/// <summary>
		/// 监视发送到窗口过程的消息，系统在消息发送到接收窗口过程之前调用
		/// </summary>
		public const int CALLWNDPROC = 4;
		/// <summary>
		/// 在以下事件之前，系统都会调用WH_CBT Hook子过程，这些事件包括： 
		/// 1. 激活，建立，销毁，最小化，最大化，移动，改变尺寸等窗口事件； 
		/// 2. 完成系统指令； 
		/// 3. 来自系统消息队列中的移动鼠标，键盘事件； 
		/// 4. 设置输入焦点事件； 
		/// 5. 同步系统消息队列事件。
		/// Hook子过程的返回值确定系统是否允许或者防止这些操作中的一个
		/// </summary>
		public const int CBT = 5;
		/// <summary>
		/// WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以监视菜单，滚动 
		/// 条，消息框，对话框消息并且发现用户使用ALT+TAB or ALT+ESC 组合键切换窗口。 
		/// WH_MSGFILTER Hook只能监视传递到菜单，滚动条，消息框的消息，以及传递到通 
		/// 过安装了Hook子过程的应用程序建立的对话框的消息。WH_SYSMSGFILTER Hook 
		/// 监视所有应用程序消息。 
		/// 
		/// WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以在模式循环期间 
		/// 过滤消息，这等价于在主消息循环中过滤消息。 
		///    
		/// 通过调用CallMsgFilter function可以直接的调用WH_MSGFILTER Hook。通过使用这 
		/// 个函数，应用程序能够在模式循环期间使用相同的代码去过滤消息，如同在主消息循 
		/// 环里一样
		/// </summary>
		public const int SYSMSGFILTER = 6;
		/// <summary>
		/// WH_MOUSE Hook监视从GetMessage 或者 PeekMessage 函数返回的鼠标消息。 
		/// 使用这个Hook监视输入到消息队列中的鼠标消息
		/// </summary>
		public const int MOUSE = 7;
		/// <summary>
		/// 当调用GetMessage 或 PeekMessage 来从消息队列种查询非鼠标、键盘消息时
		/// </summary>
		public const int HARDWARE = 8;
		/// <summary>
		/// 在系统调用系统中与其它Hook关联的Hook子过程之前，系统会调用 
		/// WH_DEBUG Hook子过程。你可以使用这个Hook来决定是否允许系统调用与其它 
		/// Hook关联的Hook子过程
		/// </summary>
		public const int DEBUG = 9;
		/// <summary>
		/// 外壳应用程序可以使用WH_SHELL Hook去接收重要的通知。当外壳应用程序是 
		/// 激活的并且当顶层窗口建立或者销毁时，系统调用WH_SHELL Hook子过程。 
		/// WH_SHELL 共有５钟情况： 
		/// 1. 只要有个top-level、unowned 窗口被产生、起作用、或是被摧毁； 
		/// 2. 当Taskbar需要重画某个按钮； 
		/// 3. 当系统需要显示关于Taskbar的一个程序的最小化形式； 
		/// 4. 当目前的键盘布局状态改变； 
		/// 5. 当使用者按Ctrl+Esc去执行Task Manager（或相同级别的程序）。 
		///
		/// 按照惯例，外壳应用程序都不接收WH_SHELL消息。所以，在应用程序能够接 
		/// 收WH_SHELL消息之前，应用程序必须调用SystemParametersInfo function注册它自 
		/// 己
		/// </summary>
		public const int SHELL = 10;
		/// <summary>
		/// 当应用程序的前台线程处于空闲状态时，可以使用WH_FOREGROUNDIDLE  
		/// Hook执行低优先级的任务。当应用程序的前台线程大概要变成空闲状态时，系统就 
		/// 会调用WH_FOREGROUNDIDLE Hook子过程
		/// </summary>
		public const int FOREGROUNDIDLE = 11;
		/// <summary>
		/// 监视发送到窗口过程的消息，系统在消息发送到接收窗口过程之后调用
		/// </summary>
		public const int CALLWNDPROCRET = 12;
		/// <summary>
		/// 监视输入到线程消息队列中的键盘消息
		/// </summary>
		public const int KEYBOARD_LL = 13;
		/// <summary>
		/// 监视输入到线程消息队列中的鼠标消息
		/// </summary>
		public const int MOUSE_LL = 14;
	}

	#endregion

	#region IMAGE_DOS_HEADER

	/// <summary>
	/// Dos 可执行文件头
	/// </summary>
	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct IMAGE_DOS_HEADER
	{      // DOS .EXE header
		public ushort e_magic;                     // Magic number
		public ushort e_cblp;                      // Bytes on last page of file
		public ushort e_cp;                        // Pages in file
		public ushort e_crlc;                      // Relocations
		public ushort e_cparhdr;                   // Size of header in paragraphs
		public ushort e_minalloc;                  // Minimum extra paragraphs needed
		public ushort e_maxalloc;                  // Maximum extra paragraphs needed
		public ushort e_ss;                        // Initial (relative) SS value
		public ushort e_sp;                        // Initial SP value
		public ushort e_csum;                      // Checksum
		public ushort e_ip;                        // Initial IP value
		public ushort e_cs;                        // Initial (relative) CS value
		public ushort e_lfarlc;                    // File address of relocation table
		public ushort e_ovno;                      // Overlay number
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.Struct)]
		public ushort[] e_res;                    // Reserved words
		public ushort e_oemid;                     // OEM identifier (for e_oeminfo)
		public ushort e_oeminfo;                   // OEM information; e_oemid specific
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10, ArraySubType = UnmanagedType.Struct)]
		public ushort[] e_res2;                  // Reserved words
		public uint e_lfanew;                    // File address of new exe header
	}

	#endregion

	#region IMAGE_FILE_HEADER

	/// <summary>
	/// PE 头数据
	/// </summary>
	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct IMAGE_FILE_HEADER
	{
		/*
		#define IMAGE_FILE_MACHINE_UNKNOWN           0
		#define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
		#define IMAGE_FILE_MACHINE_R3000             0x0162  // MIPS little-endian, 0x160 big-endian
		#define IMAGE_FILE_MACHINE_R4000             0x0166  // MIPS little-endian
		#define IMAGE_FILE_MACHINE_R10000            0x0168  // MIPS little-endian
		#define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169  // MIPS little-endian WCE v2
		#define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP
		#define IMAGE_FILE_MACHINE_SH3               0x01a2  // SH3 little-endian
		#define IMAGE_FILE_MACHINE_SH3DSP            0x01a3
		#define IMAGE_FILE_MACHINE_SH3E              0x01a4  // SH3E little-endian
		#define IMAGE_FILE_MACHINE_SH4               0x01a6  // SH4 little-endian
		#define IMAGE_FILE_MACHINE_SH5               0x01a8  // SH5
		#define IMAGE_FILE_MACHINE_ARM               0x01c0  // ARM Little-Endian
		………………….
		#define IMAGE_FILE_MACHINE_CEE               0xC0EE
		*/
		public ushort Machine;                //运行平台
		public ushort NumberOfSections;        //文件区块数目
		public uint TimeDateStamp;            //文件创建日期和时间
		public uint PointerToSymbolTable;    //指向符号表（主要用于调试）
		public uint NumberOfSymbols;        //符号表中符号个数
		public ushort SizeOfOptionalHeader;        //IMAGE_OPTIONAL_HEADER32 结构大小
												   /*
												   #define IMAGE_FILE_RELOCS_STRIPPED　　 0x0001　// 重定位信息被移除 
												   #define IMAGE_FILE_EXECUTABLE_IMAGE   0x0002　// 文件可执行 
												   #define IMAGE_FILE_LINE_NUMS_STRIPPED  0x0004　// 行号被移除 
												   #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008　// 符号被移除 
												   ……..
												   #define IMAGE_FILE_32BIT_MACHINE  0x0100　// 32位机器 
												   #define IMAGE_FILE_DEBUG_STRIPPED 0x0200　// .dbg文件的调试信息被移除 
												   ………………….
												   #define IMAGE_FILE_SYSTEM　　　　　　　0x1000　// 系统文件 
												   #define IMAGE_FILE_DLL　　　　　　　　　0x2000　// 文件是一个dll 
												   #define IMAGE_FILE_UP_SYSTEM_ONLY    0x4000　// 文件只能运行在单处理器上
												   */
		public ushort Characteristics;            //文件属性
	}

	#endregion

	#region IMAGE_DATA_DIRECTORY

	/// <summary>
	/// 
	/// </summary>
	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct IMAGE_DATA_DIRECTORY
	{
		public uint VirtualAddress;
		public uint Size;
	}

	#endregion

	#region IMAGE_OPTIONAL_HEADER32

	/// <summary>
	/// PE 可选头信息
	/// </summary>
	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct IMAGE_OPTIONAL_HEADER32
	{
		/// <summary>
		/// 映像文件的状态//0x010B
		/// </summary>
		public ushort Magic;
		/// <summary>
		/// 连接器的主版本号
		/// </summary>
		public byte MajorLinkerVersion;
		/// <summary>
		/// 连接器的次版本号
		/// </summary>
		public byte MinorLinkerVersion;
		/// <summary>
		/// 代码段的大小，如果有多个代码段则为总和
		/// </summary>
		public uint SizeOfCode;
		/// <summary>
		/// 初始化数据段大小.如果多个则为总和
		/// </summary>
		public uint SizeOfInitializedData;
		/// <summary>
		/// 未初始化数据段大小，.如果多个则为总和.bbs
		/// </summary>
		public uint SizeOfUninitializedData;
		/// <summary>
		/// PE文件入口地址的RAV：OEP = ImageBase + RAV
		/// </summary>
		public uint AddressOfEntryPoint;
		/// <summary>
		/// 代码块起始地址的RVA
		/// </summary>
		public uint BaseOfCode;
		///数据块的起始地址的RVA
		public uint BaseOfData;
		// NT additional fields.
		/// <summary>
		/// 可执行文件的基址ImageBase
		/// </summary>
		public uint ImageBase;
		/// <summary>
		/// 每一个块必须保证始于这个值的整数倍
		/// </summary>
		public uint SectionAlignment;
		/// <summary>
		/// 对齐映射文件部分原始数据 2 or 512 or 64： 默认为512
		/// </summary>
		public uint FileAlignment;
		/// <summary>
		/// 要求的操作系统的主版本号
		/// </summary>
		public ushort MajorOperatingSystemVersion;
		/// <summary>
		/// 要求的操作系统的次版本号
		/// </summary>
		public ushort MinorOperatingSystemVersion;
		/// <summary>
		/// 映像的主版本号
		/// </summary>
		public ushort MajorImageVersion;
		/// <summary>
		/// 映像的次版本号
		/// </summary>
		public ushort MinorImageVersion;
		/// <summary>
		/// 子系统的主版本号
		/// </summary>
		public ushort MajorSubsystemVersion;
		/// <summary>
		/// 子系统的次版本号
		/// </summary>
		public ushort MinorSubsystemVersion;
		/// <summary>
		/// 保留值.必须为0
		/// </summary>
		public uint Win32VersionValue;
		/// <summary>
		/// 映像文件的大小
		/// </summary>
		public uint SizeOfImage;
		/// <summary>
		/// 映像文件的头大小
		/// </summary>
		public uint SizeOfHeaders;
		/// <summary>
		/// 映像文件的校验和
		/// </summary>
		public uint CheckSum;
		/// <summary>
		/// 运行此映像的字系统
		/// </summary>
		public ushort Subsystem;
		/// <summary>
		/// 映像文件的DLL特征
		/// </summary>
		public ushort DllCharacteristics;
		/// <summary>
		/// 堆栈保留字节. 0x100000
		/// </summary>
		public uint SizeOfStackReserve;
		/// <summary>
		/// 线程开始提交的初始堆栈大小
		/// </summary>
		public uint SizeOfStackCommit;
		/// <summary>
		/// 为初始进程保留的虚拟内存总数
		/// </summary>
		public uint SizeOfHeapReserve;
		/// <summary>
		/// 进程开始提交初始虚拟内存的大小
		/// </summary>
		public uint SizeOfHeapCommit;
		public uint LoaderFlags;
		//0x10
		public uint NumberOfRvaAndSizes;
		/*
		#define IMAGE_DIRECTORY_ENTRY_EXPORT            0   // Export Directory
		#define IMAGE_DIRECTORY_ENTRY_IMPORT             1   // Import Directory
		#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory
		#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory
		#define IMAGE_DIRECTORY_ENTRY_SECURITY          4   // Security Directory
		#define IMAGE_DIRECTORY_ENTRY_BASERELOC        5   // Base Relocation Table
		#define IMAGE_DIRECTORY_ENTRY_DEBUG             6   // Debug Directory
		//      IMAGE_DIRECTORY_ENTRY_COPYRIGHT        7   // (X86 usage)
		#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE  7   // Architecture Specific Data
		#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR         8   // RVA of GP
		#define IMAGE_DIRECTORY_ENTRY_TLS                 9   // TLS Directory
		#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10 // Load Configuration Directory
		#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT     11 // Bound Import Directory in headers
		#define IMAGE_DIRECTORY_ENTRY_IAT              12   // Import Address Table
		#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT    13   // Delay Load Import Descriptors
		#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor
		*/
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16, ArraySubType = UnmanagedType.Struct)]
		public IMAGE_DATA_DIRECTORY[] DataDirectory;//#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16
													//指向第一个IMAGE_DATA_DIRECTORY
	}

	#endregion

	#region IMAGE_NT_HEADERS32

	/// <summary>
	/// WinNT PE 头信息
	/// </summary>
	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct IMAGE_NT_HEADERS32
	{
		public uint Signature; //4 bytes PE文件头标志：(e_lfanew)->‘PE’
		public IMAGE_FILE_HEADER FileHeader;//20 bytes PE文件物理分布的信息
		public IMAGE_OPTIONAL_HEADER32 OptionalHeader;//224bytes PE文件逻辑分布的信息
	}

	#endregion

	#region IMAGE_SECTION_HEADER

	/// <summary>
	/// PE 段信息
	/// </summary>
	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct IMAGE_SECTION_HEADER//PIMAGE_SECTION_HEADER
	{
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.Struct)]
		public byte[] Name;//#define IMAGE_SIZEOF_SHORT_NAME   8
		public uint PhysicalAddress_or_VirtualSize;
		public uint VirtualAddress;    //内存中偏移地址
		public uint SizeOfRawData;    //PE文件中对其之后的大小
		public uint PointerToRawData;//为PE块区在PE文件中偏移
		public uint PointerToRelocations;
		public uint PointerToLinenumbers;
		public ushort NumberOfRelocations;
		public ushort NumberOfLinenumbers;
		public uint Characteristics;    //块区的属性：可读、可写..
	}

	#endregion

	/// <summary/>
	public static class MF
	{
		/// <summary/>
		[Flags]
		public enum E
		{
			/// <summary/>
			ByPosition = BYPOSITION,
		}

		/// <summary/>
		public const int BYPOSITION = 0x0400;
	}

	/// <summary/>
	public delegate bool EnumWinProc(IntPtr hwnd, IntPtr lParam);
}
